<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Andrey Listopadov</title>
    <link>https://andreyor.st/</link>
    <image>
      <title>Andrey Listopadov</title>
      <link>https://andreyor.st/</link>
      <url>https://andreyor.st/favicon-64.png</url>
    </image>
    <description>All posts by Andrey Listopadov</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>Andrey Listopadov 2020-2026 - This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</copyright>
    <lastBuildDate>Tue, 07 Apr 2026 02:47:00 +0300</lastBuildDate>
    <atom:link href="https://andreyor.st/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Clojure on Fennel part one: Persistent Data Structures</title>
      <link>https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/</link>
      <guid>https://andreyor.st/posts/2026-04-07-clojure-on-fennel-part-one-persistent-data-structures/</guid>
      <description>&lt;p&gt;Somewhere in 2019 I started a project that aimed to bring some of Clojure features to Lua runtime - &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;.
It was a library for Fennel that implemented a basic subset of &lt;code&gt;clojure.core&lt;/code&gt; namespace functions and macros.
My goal was simple - I enjoy working with Clojure, but I don&amp;rsquo;t use it for hobby projects, so I wanted Fennel to feel more Clojure-like, besides what it already provides for that.&lt;/p&gt;
&lt;p&gt;This library grew over the years, I implemented &lt;a href=&#34;https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/&#34;&gt;lazy sequences&lt;/a&gt;, added &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;immutability&lt;/a&gt;, made a &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test&#34; target=&#34;_blank&#34;&gt;testing library&lt;/a&gt;, inspired by &lt;code&gt;clojure.test&lt;/code&gt; and kaocha, and even made a &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;port of &lt;code&gt;clojure.core.async&lt;/code&gt;&lt;/a&gt;.
It was a passion project, I almost never used it to write actual software.
One notable exception is &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;fenneldoc&lt;/a&gt; - a tool for documentation generation for Fennel libraries.
And I haven&amp;rsquo;t seen anyone else use it for a serious project.&lt;/p&gt;
&lt;p&gt;The reason for that is simple - it was an experiment.
Corners were cut, and Fennel, being a Clojure-inspired lisp is not associated with functional programming the same way Clojure is.
As a matter of fact, I wouldn&amp;rsquo;t recommend using this library for anything serious&amp;hellip; yet.&lt;/p&gt;
&lt;p&gt;Recently, however, I started a new project: &lt;a href=&#34;https://gitlab.com/andreyorst/clojurefnl&#34; target=&#34;_blank&#34;&gt;ClojureFnl&lt;/a&gt;.
This is a Clojure-to-Fennel compiler that uses fennel-cljlib as a foundation.
It&amp;rsquo;s still in early days of development, but I&amp;rsquo;ve been working on it for a few months in private until I found a suitable way to make things work in March.
As of this moment, it is capable of compiling most of &lt;code&gt;.cljc&lt;/code&gt; files I threw at it, but running the compiled code is a different matter.
I mean, it works to some degree, but the support for standard library is far from done.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Welcome to ClojureFnl REPL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ClojureFnl v0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel 1.6.1 on PUC Lua 5.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prime?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;some zero? &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rem &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x89ba7c550&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;3 33 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prime?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(3 5 7 11 13 17 19 23 29 31)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, there was a problem.&lt;/p&gt;
&lt;p&gt;My initial implementation of immutable data structures in the &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;itable&lt;/a&gt; library had a serious flaw.
The whole library was a simple hack based on the copy-on-write approach and a bunch of Lua metatables to enforce immutability.
As a result, all operations were extremely slow.
It was fine as an experiment, but if I wanted to go further with ClojureFnl, I had to replace it.
The same problem plagued &lt;a href=&#34;https://gitlab.com/andreyorst/immutableredblacktree.lua&#34; target=&#34;_blank&#34;&gt;immutableredblacktree.lua&lt;/a&gt;, an implementation of a copy-on-write red-black tree I made for sorted maps.
It did a full copy of the tree each time it was modified.&lt;/p&gt;
&lt;p&gt;For associative tables it wasn&amp;rsquo;t that big of a deal - usually maps contain a small amount of keys, and &lt;code&gt;itable&lt;/code&gt; only copied levels that needed to be changed.
So, if you had a map with, say, ten keys, and each of those keys contained another map with ten keys, adding, removing or updating a key in the outer map meant only copying these ten keys - not the whole nested map.
I could do that reliably, because inner maps were immutable too.&lt;/p&gt;
&lt;p&gt;But for arrays the story is usually quite different.
Arrays often store a lot of indices, and rarely are nested (or at least not as often as maps).
And copying arrays on every change quickly becomes expensive.
I&amp;rsquo;ve mitigated some of the performance problems by implementing my version of transients, however the beauty of Clojure&amp;rsquo;s data structures is that they&amp;rsquo;re quite fast even without this optimization.&lt;/p&gt;
&lt;h2 id=&#34;proper-persistent-data-structures&#34;&gt;Proper persistent data structures&lt;/h2&gt;
&lt;p&gt;Clojure uses Persistent HAMT as a base for its hash maps and sets, and a bit-partitioned trie for vectors.
For sorted maps and sets, Clojure uses an immutable red-black tree implementation, but as far as I know it&amp;rsquo;s not doing a full copy of the tree, and it also has structural sharing properties.&lt;/p&gt;
&lt;p&gt;I started looking into existing implementations of HAMT for Lua:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/raymond-w-ko/hamt.lua&#34; target=&#34;_blank&#34;&gt;hamt.lua&lt;/a&gt; (based on &lt;a href=&#34;https://github.com/mattbierner/hamt.git&#34; target=&#34;_blank&#34;&gt;mattbierner/hamt&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;seemed incomplete&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/alloyed/ltrie&#34; target=&#34;_blank&#34;&gt;ltrie&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;no transients&lt;/li&gt;
&lt;li&gt;no hashset&lt;/li&gt;
&lt;li&gt;no ordered map (expectable, different algorithm)&lt;/li&gt;
&lt;li&gt;no compound vector/hash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/SegFaultAX/3318559&#34; target=&#34;_blank&#34;&gt;Michael-Keith Bernard&amp;rsquo;s gist&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;no custom hashing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I could use one of those, notably &lt;code&gt;ltrie&lt;/code&gt; seemed the most appropriate one, but given that I&amp;rsquo;m working on a fennel library that I want later to embed into my Clojure compiler I needed a library implemented in Fennel.&lt;/p&gt;
&lt;p&gt;So I made my own library: &lt;a href=&#34;https://gitlab.com/andreyorst/immutable.fnl&#34; target=&#34;_blank&#34;&gt;immutable.fnl&lt;/a&gt;.
This library features HAMT-hash maps, hash-sets, and vectors, as well as a better implementation of a persistent red-black tree, and lazy linked lists.&lt;/p&gt;
&lt;h3 id=&#34;persistent-hash-map&#34;&gt;Persistent Hash Map&lt;/h3&gt;
&lt;p&gt;I started the implementation with a Persistent HAMT with native Lua hashing.
The data structure itself is a Hash Array Mapped Trie (HAMT) with 16-factor branching.
Thus all operations are O(Log16 N), which is effectively O(1) for a practical amount of keys.&lt;/p&gt;
&lt;p&gt;As far as I know, Clojure uses branching factor of 32, but for a Lua runtime this would mean that the popcount would be more expensive, and despite a shallower tree, each mutation would need to copy a larger sparse array.
With branching factor of 16 a map with 50K entries is ~4 levels deep, which would be ~3 with 32 branching factor.
So my logic was that it&amp;rsquo;ll be a compromise, especially since Lua is not JVM when it comes to performance.&lt;/p&gt;
&lt;p&gt;Of course, it&amp;rsquo;s not as fast as a pure Lua table, which is to be expected.
Lua tables are implemented in C, use efficient hashing, and dynamically re-allocated based on key count.
So for my implementation most operations are a lot slower, but the total time for an operation is still usable.&lt;/p&gt;
&lt;p&gt;Here are some benchmarks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on PUC Lua 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Regular operations are notably slower, when compared to Lua:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;2.05 ms&lt;/td&gt;
&lt;td&gt;164.80 ms&lt;/td&gt;
&lt;td&gt;80.3x slower&lt;/td&gt;
&lt;td&gt;3.3 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.83 ms&lt;/td&gt;
&lt;td&gt;92.51 ms&lt;/td&gt;
&lt;td&gt;110.8x slower&lt;/td&gt;
&lt;td&gt;1.9 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.78 ms&lt;/td&gt;
&lt;td&gt;170.78 ms&lt;/td&gt;
&lt;td&gt;219.8x slower&lt;/td&gt;
&lt;td&gt;3.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;19.50 ms&lt;/td&gt;
&lt;td&gt;136.4x slower&lt;/td&gt;
&lt;td&gt;3.9 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 entries&lt;/td&gt;
&lt;td&gt;1.74 ms&lt;/td&gt;
&lt;td&gt;6.64 ms&lt;/td&gt;
&lt;td&gt;3.8x slower&lt;/td&gt;
&lt;td&gt;0.133 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For transients the situation is a bit better, but not by much:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;2.05 ms&lt;/td&gt;
&lt;td&gt;89.17 ms&lt;/td&gt;
&lt;td&gt;43.5x slower&lt;/td&gt;
&lt;td&gt;1.8 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.76 ms&lt;/td&gt;
&lt;td&gt;104.31 ms&lt;/td&gt;
&lt;td&gt;138.0x slower&lt;/td&gt;
&lt;td&gt;2.1 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.16 ms&lt;/td&gt;
&lt;td&gt;12.71 ms&lt;/td&gt;
&lt;td&gt;82.0x slower&lt;/td&gt;
&lt;td&gt;2.5 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On LuaJIT numbers may seem worse, but per-operation cost is much lower, it&amp;rsquo;s just that native table operations are so much faster:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on LuaJIT 2.1.1774896198 macOS/arm64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;0.86 ms&lt;/td&gt;
&lt;td&gt;49.05 ms&lt;/td&gt;
&lt;td&gt;56.8x slower&lt;/td&gt;
&lt;td&gt;0.981 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.27 ms&lt;/td&gt;
&lt;td&gt;14.21 ms&lt;/td&gt;
&lt;td&gt;53.4x slower&lt;/td&gt;
&lt;td&gt;0.284 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.13 ms&lt;/td&gt;
&lt;td&gt;48.63 ms&lt;/td&gt;
&lt;td&gt;374.1x slower&lt;/td&gt;
&lt;td&gt;0.973 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.05 ms&lt;/td&gt;
&lt;td&gt;6.49 ms&lt;/td&gt;
&lt;td&gt;138.1x slower&lt;/td&gt;
&lt;td&gt;1.3 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 entries&lt;/td&gt;
&lt;td&gt;0.07 ms&lt;/td&gt;
&lt;td&gt;1.80 ms&lt;/td&gt;
&lt;td&gt;27.7x slower&lt;/td&gt;
&lt;td&gt;0.036 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient HashMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;0.76 ms&lt;/td&gt;
&lt;td&gt;22.43 ms&lt;/td&gt;
&lt;td&gt;29.6x slower&lt;/td&gt;
&lt;td&gt;0.449 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.15 ms&lt;/td&gt;
&lt;td&gt;34.16 ms&lt;/td&gt;
&lt;td&gt;232.4x slower&lt;/td&gt;
&lt;td&gt;0.683 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete 10%&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;5.02 ms&lt;/td&gt;
&lt;td&gt;132.1x slower&lt;/td&gt;
&lt;td&gt;1.0 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With a branching factor of 32 the situation gets worse on PUC Lua, but is slightly better on LuaJIT.
So there&amp;rsquo;s still space for fine-tuning.&lt;/p&gt;
&lt;p&gt;For hashing strings and objects I decided to use &lt;code&gt;djb2&lt;/code&gt; algorithm.
I am almost as old as this hash function, so seemed like a good fit.
JK.
The main reason to use it was that it can be implemented even if we don&amp;rsquo;t have any bit-wise operators, and Lua doesn&amp;rsquo;t have them in all of the versions.
It only uses &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, and &lt;code&gt;%&lt;/code&gt; arithmetic operators, so can be done on any Lua version.
It&amp;rsquo;s prone to collisions, and I try to mitigate that by randomizing it when the library is loaded.&lt;/p&gt;
&lt;p&gt;Still, collisions do happen, but HAMT core ensures that they will still resolve correctly by implementing a deep equality function for most objects.&lt;/p&gt;
&lt;p&gt;However, when first working on this, I noticed this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.immutable.PersistentHashMap&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.immutable.impl.hash&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;161272824
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;161272824
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2) 1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is an interesting loophole. What object ended up in our hash map as a key - our persistent map or plain Lua table?
Well, that depends on insertion order:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2) 1 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IPersistentHashMap&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x824d9b570&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2} 2 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash-map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 2) 1))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To &lt;em&gt;reiterate&lt;/em&gt;, I&amp;rsquo;m creating a hash map, with a key set to another persistent hash map, and then insert a plain Lua table with the same content.
The Lua table hashes to exactly the same hash, and goes into the same bucket, but there&amp;rsquo;s no collision, because &lt;em&gt;objects are equal by value&lt;/em&gt;.
But equality of mutable collections is very loosely defined - it may be equal right now, but the next time you look at it, it&amp;rsquo;s different.
So a different hashing was needed for persistent collections, to avoid these kinds of collision.
I ended up salting persistent collections with their prototype address in memory.&lt;/p&gt;
&lt;p&gt;Other than that, the HAMT implementation is by the book, and the rest is the interface for interacting with maps.&lt;/p&gt;
&lt;p&gt;Main operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; - construct a new map of key value pairs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assoc&lt;/code&gt; - associate a key with a value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dissoc&lt;/code&gt; - remove key from the map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conj&lt;/code&gt; - universal method for association, much like in Clojure&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contains&lt;/code&gt; - check if key is in the map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt; - map size, constant time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get&lt;/code&gt; - get a key value from a map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keys&lt;/code&gt; - get a lazy list of keys&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vals&lt;/code&gt; - get a lazy list of values&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transient&lt;/code&gt; - convert a map to a transient&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Coercion/conversion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - create a map from another object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;to-table&lt;/code&gt; - convert a map to a Lua table&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator&lt;/code&gt; - get an iterator to use in Lua loops&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transient operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assoc!&lt;/code&gt; - mutable &lt;code&gt;assoc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dissoc!&lt;/code&gt; - mutable &lt;code&gt;dissoc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;persistent&lt;/code&gt; - convert back to persistent variant, and mark transient as completed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This covers most of the needs in my &lt;code&gt;fennel-cljlib&lt;/code&gt; library, as anything besides it I can implement myself, or just adapt existing implementations.&lt;/p&gt;
&lt;p&gt;A Persistent Hash Set is also available as a thin wrapper around &lt;code&gt;PersistentHashMap&lt;/code&gt; with a few method changes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A note on &lt;code&gt;PersistentArrayMap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In Clojure there is a second kind of maps that are ordered, not sorted, called a Persistent Array Map.
They are used by default when defining a map with eight keys or less, like &lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;.
The idea is simple - for such a small map, a linear search through all keys is faster than with a HAMT-based map.&lt;/p&gt;
&lt;p&gt;However, in my testing on the Lua runtime, there&amp;rsquo;s no benefit in this kind of a data structure, apart from it being an ordered variant.
Lookup is slower, because of a custom equality function, which does deep comparison.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;persistent-vector&#34;&gt;Persistent Vector&lt;/h3&gt;
&lt;p&gt;Persistent Vectors came next, and while the trie structure is similar to hash maps, vectors use direct index-based navigation instead of hashing, with a branching factor of 32.
Unlike maps, vector arrays in the HAMT are more densely packed, and therefore a higher branching factor is better for performance.
So lookup, update, and pop are O(log32 N), append can be considered O(1) amortized.&lt;/p&gt;
&lt;p&gt;Still, compared to plain Lua sequential tables the performance is not as good:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on PUC Lua 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 elements&lt;/td&gt;
&lt;td&gt;0.19 ms&lt;/td&gt;
&lt;td&gt;21.07 ms&lt;/td&gt;
&lt;td&gt;109.7x slower&lt;/td&gt;
&lt;td&gt;0.421 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random indices&lt;/td&gt;
&lt;td&gt;0.47 ms&lt;/td&gt;
&lt;td&gt;14.05 ms&lt;/td&gt;
&lt;td&gt;29.7x slower&lt;/td&gt;
&lt;td&gt;0.281 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.32 ms&lt;/td&gt;
&lt;td&gt;70.04 ms&lt;/td&gt;
&lt;td&gt;221.6x slower&lt;/td&gt;
&lt;td&gt;1.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.25 ms&lt;/td&gt;
&lt;td&gt;24.34 ms&lt;/td&gt;
&lt;td&gt;96.2x slower&lt;/td&gt;
&lt;td&gt;0.487 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 elements&lt;/td&gt;
&lt;td&gt;0.63 ms&lt;/td&gt;
&lt;td&gt;10.16 ms&lt;/td&gt;
&lt;td&gt;16.2x slower&lt;/td&gt;
&lt;td&gt;0.203 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000  elements&lt;/td&gt;
&lt;td&gt;0.19 ms&lt;/td&gt;
&lt;td&gt;7.81 ms&lt;/td&gt;
&lt;td&gt;40.3x slower&lt;/td&gt;
&lt;td&gt;0.156 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.33 ms&lt;/td&gt;
&lt;td&gt;20.76 ms&lt;/td&gt;
&lt;td&gt;62.4x slower&lt;/td&gt;
&lt;td&gt;0.415 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.25 ms&lt;/td&gt;
&lt;td&gt;11.14 ms&lt;/td&gt;
&lt;td&gt;44.4x slower&lt;/td&gt;
&lt;td&gt;0.223 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On LuaJIT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on LuaJIT 2.1.1774896198 macOS/arm64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Persistent Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 elements&lt;/td&gt;
&lt;td&gt;0.10 ms&lt;/td&gt;
&lt;td&gt;7.62 ms&lt;/td&gt;
&lt;td&gt;74.0x slower&lt;/td&gt;
&lt;td&gt;0.152 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random indices&lt;/td&gt;
&lt;td&gt;0.06 ms&lt;/td&gt;
&lt;td&gt;0.67 ms&lt;/td&gt;
&lt;td&gt;11.8x slower&lt;/td&gt;
&lt;td&gt;0.013 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;29.13 ms&lt;/td&gt;
&lt;td&gt;710.4x slower&lt;/td&gt;
&lt;td&gt;0.583 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;8.62 ms&lt;/td&gt;
&lt;td&gt;410.4x slower&lt;/td&gt;
&lt;td&gt;0.172 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iterate 50000 elements&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;0.57 ms&lt;/td&gt;
&lt;td&gt;28.7x slower&lt;/td&gt;
&lt;td&gt;0.011 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;Transient Vector&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 elements&lt;/td&gt;
&lt;td&gt;0.05 ms&lt;/td&gt;
&lt;td&gt;0.59 ms&lt;/td&gt;
&lt;td&gt;11.6x slower&lt;/td&gt;
&lt;td&gt;0.012 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;update 50000 random indices&lt;/td&gt;
&lt;td&gt;0.04 ms&lt;/td&gt;
&lt;td&gt;2.06 ms&lt;/td&gt;
&lt;td&gt;51.6x slower&lt;/td&gt;
&lt;td&gt;0.041 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop all 50000 elements&lt;/td&gt;
&lt;td&gt;0.02 ms&lt;/td&gt;
&lt;td&gt;0.84 ms&lt;/td&gt;
&lt;td&gt;46.7x slower&lt;/td&gt;
&lt;td&gt;0.017 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;I think this is an OK performance still.
Vectors don&amp;rsquo;t use hashing, instead it is a direct index traversal via bit-shifting, so there&amp;rsquo;s no hashing, just index math.&lt;/p&gt;
&lt;p&gt;Operations on vectors include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; - constructor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conj&lt;/code&gt; - append to the tail&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assoc&lt;/code&gt; - change a value at given index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt; - element count (constant time)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get&lt;/code&gt; - get value at given index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pop&lt;/code&gt; - remove last&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transient&lt;/code&gt; - convert to a transient&lt;/li&gt;
&lt;li&gt;&lt;code&gt;subvec&lt;/code&gt; - create a slice of the vector in constant time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transient operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assoc!&lt;/code&gt; - mutable &lt;code&gt;assoc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conj!&lt;/code&gt; - mutable &lt;code&gt;conj&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pop!&lt;/code&gt; - mutable &lt;code&gt;pop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;persistent&lt;/code&gt; - convert back to persistent and finalize&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Interop:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;from&lt;/code&gt; - creates a vector from any other collection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator&lt;/code&gt; - returns an iterator for use in Lua loops&lt;/li&gt;
&lt;li&gt;&lt;code&gt;to-table&lt;/code&gt; - converts to a sequential Lua table&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One notable difference in both vector and hash-map is that it allows &lt;code&gt;nil&lt;/code&gt; to be used as a value (and as a key, in case of the hash-map).
Vectors don&amp;rsquo;t have the same problem that Lua sequential tables have, where length is not well-defined if the table has holes in it.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a debate for another time, whether allowing &lt;code&gt;nil&lt;/code&gt; as a value (and especially as a key) is a good decision to make, but Clojure already made it for me.
So for this project I decided to support it.&lt;/p&gt;
&lt;h3 id=&#34;persistent-red-black-tree&#34;&gt;Persistent Red-Black Tree&lt;/h3&gt;
&lt;p&gt;For sorted maps and sorted sets I chose Okasaki&amp;rsquo;s insertion and Germane &amp;amp; Might&amp;rsquo;s deletion algorithms.
Most of the knowledge I got from this amazing &lt;a href=&#34;https://matt.might.net/articles/red-black-delete/&#34; target=&#34;_blank&#34;&gt;blog post&lt;/a&gt; by Matt Might.&lt;/p&gt;
&lt;p&gt;I believe the operations are O(Log N), as for any binary tree, but given that the deletion algorithm is tricky, I&amp;rsquo;m not exactly sure:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on PUC Lua 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;PersistentTreeMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;2.10 ms&lt;/td&gt;
&lt;td&gt;209.23 ms&lt;/td&gt;
&lt;td&gt;99.8x slower&lt;/td&gt;
&lt;td&gt;4.2 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.88 ms&lt;/td&gt;
&lt;td&gt;82.97 ms&lt;/td&gt;
&lt;td&gt;94.2x slower&lt;/td&gt;
&lt;td&gt;1.7 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.74 ms&lt;/td&gt;
&lt;td&gt;173.76 ms&lt;/td&gt;
&lt;td&gt;234.8x slower&lt;/td&gt;
&lt;td&gt;3.5 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On LuaJIT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Median time over 7 rounds (1 warmup discarded), N = 50000 elements.
GC stopped during measurement. Clock: os.clock (CPU).
Runtime: Fennel 1.7.0-dev on LuaJIT 2.1.1774896198 macOS/arm64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lua table&lt;/th&gt;
&lt;th&gt;PersistentTreeMap&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;th&gt;per op&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;insert 50000 random keys&lt;/td&gt;
&lt;td&gt;0.72 ms&lt;/td&gt;
&lt;td&gt;101.08 ms&lt;/td&gt;
&lt;td&gt;140.4x slower&lt;/td&gt;
&lt;td&gt;2.0 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lookup 50000 random keys&lt;/td&gt;
&lt;td&gt;0.25 ms&lt;/td&gt;
&lt;td&gt;12.67 ms&lt;/td&gt;
&lt;td&gt;49.9x slower&lt;/td&gt;
&lt;td&gt;0.253 us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete all&lt;/td&gt;
&lt;td&gt;0.14 ms&lt;/td&gt;
&lt;td&gt;56.14 ms&lt;/td&gt;
&lt;td&gt;403.9x slower&lt;/td&gt;
&lt;td&gt;1.1 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The API for sorted maps and sets is the same as to their hash counterparts with a small difference - no transients.
Clojure doesn&amp;rsquo;t do them, and I&amp;rsquo;m not doing them too.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for benchmarks.
I know that there are many problems with this kind of benchmarking, so take it with a grain of salt.
Still, the results are far, far better than what I had with &lt;code&gt;itable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But there are two more data structures to talk about.&lt;/p&gt;
&lt;h3 id=&#34;persistent-list&#34;&gt;Persistent List&lt;/h3&gt;
&lt;p&gt;As I mentioned, I made a lazy persistent list implementation a while ago but it had its problems and I couldn&amp;rsquo;t integrate that library with the current one well enough.&lt;/p&gt;
&lt;p&gt;The main problem was that this library uses a single shared metatable per data structure, and the old implementation of lazy lists didn&amp;rsquo;t.
This difference makes it hard to check whether the object is a table, hash-map, list, vector, set, etc.
So I reimplemented them.&lt;/p&gt;
&lt;p&gt;The reason for old implementation to use different metatables was because I decided to try the approach described in &lt;a href=&#34;https://aphyr.com/posts/340-reversing-the-technical-interview&#34; target=&#34;_blank&#34;&gt;Reversing the technical interview&lt;/a&gt; post by Kyle Kingsbury (Aphyr).
I know this post is more of a fun joke, but it actually makes sense to define linked lists like that in Lua.&lt;/p&gt;
&lt;p&gt;See, tables are mutable, and you can&amp;rsquo;t do much about it.
Closures, on the other hand are much harder to mutate - you can still do it via the &lt;code&gt;debug&lt;/code&gt; module, but it&amp;rsquo;s hard, and it&amp;rsquo;s not always present.
So storing &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt; in function closures was a deliberate choice.&lt;/p&gt;
&lt;p&gt;However, it meant that I needed to somehow attach metadata to the function, to make it act like a data structure, and you can&amp;rsquo;t just use &lt;code&gt;setmetatable&lt;/code&gt; on a function.
Again, you can do &lt;code&gt;debug.setmetatable&lt;/code&gt; but all function objects share the same metadata table.
So, while you can do fancy things like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comp&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x7bdb320a0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.setmetatable &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[]) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comp&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x7bd17f040&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; ((&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.reverse &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.upper&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also notice, that our &lt;code&gt;+&lt;/code&gt; overload applied to functions in the string module.&lt;/p&gt;
&lt;p&gt;So instead, we use a table, and wrap it with a metatable that has a &lt;code&gt;__call&lt;/code&gt; metamethod, essentially making our table act like a function.
This, in turn means, that we have to create two tables per list node - one to give to the user, the other to set our &lt;code&gt;__call&lt;/code&gt; and use it as a meta-table.&lt;/p&gt;
&lt;p&gt;Convoluted, I know.
It&amp;rsquo;s all in the past now - current implementation is a simple &lt;code&gt;{:head 42 :tail {...}}&lt;/code&gt; table.
Not sure what is worse.&lt;/p&gt;
&lt;p&gt;But that meant that I had to rework how lazy lists worked, because previously it was just a metatable swap.
Now list stores a &amp;ldquo;thunk&amp;rdquo;, that when called replaces itself in the node with the &lt;code&gt;:head&lt;/code&gt; and &lt;code&gt;:tail&lt;/code&gt; keys.
Unless it&amp;rsquo;s an empty list, of course - in that case we swap the metatable to an empty list one.&lt;/p&gt;
&lt;p&gt;So Lists have three metatables now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IPersistentList&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPersistentList$Empty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPersistentList$Lazy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instead of god knows how many in the old implementation.&lt;/p&gt;
&lt;p&gt;The list interface is also better now.
Previously it was hardcoded how to construct a list from a data structure.
Current implementation also hardcodes it, but also allows to build a list in a lazy way from an iterator.&lt;/p&gt;
&lt;p&gt;This is better, because now a custom data structure that has weird iteration schema (like maps and sets in this library), we still can convert it to a list.
A general case is just:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PersistentList.from-iterator&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Meaning that we pass a function that will produce the iterator, and a function to capture values from that iterator.
Reminds me of clojure transducers in some way.&lt;/p&gt;
&lt;h3 id=&#34;persistent-queue&#34;&gt;Persistent Queue&lt;/h3&gt;
&lt;p&gt;And the final data structure - a persistent queue.
Fast append at the end, and also fast remove from the front.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s done by holding two collections - a linked list at the front, and a persistent vector for the rear.
So removing from the list is O(1), and appending to the vector is also pretty much O(1).&lt;/p&gt;
&lt;p&gt;Interesting things start to happen when we exhaust the list part - we need to move vector&amp;rsquo;s contents into the list.
It is done by calling &lt;code&gt;PersistentList.from&lt;/code&gt; on the rear.
And building a list out of a persistent vector is an O(1) operation as well!
Well, because nothing happens, we simply create an iterator, and build the list in a lazy way.
But since indexing the vector is essentially ~O(1), we can say that we still retain this property.&lt;/p&gt;
&lt;p&gt;Or at least that&amp;rsquo;s how I reasoned about this - I&amp;rsquo;m not that good with time-complexity stuff.&lt;/p&gt;
&lt;h2 id=&#34;clojurefnl&#34;&gt;ClojureFnl&lt;/h2&gt;
&lt;p&gt;That concludes part one about ClojureFnl.&lt;/p&gt;
&lt;p&gt;I know that this post was not about ClojureFnl at all, but I had to fix my underlying implementation first.
Now, that I have better data structures to build from, I can get back working on the compiler itself.
So the next post will hopefully be about the compiler itself.&lt;/p&gt;
&lt;p&gt;Unless I get distracted again.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure on Fennel part one: Persistent Data Structures&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 07 Apr 2026 02:47:00 +0300</pubDate>
    </item><item>
      <title>Slopes in AABB collision systems</title>
      <link>https://andreyor.st/posts/2026-01-09-slopes-in-aabb-collision-systems/</link>
      <guid>https://andreyor.st/posts/2026-01-09-slopes-in-aabb-collision-systems/</guid>
      <description>&lt;p&gt;Recently (again, &lt;a href=&#34;https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/&#34;&gt;bored on a vacation&lt;/a&gt;), I started working on a game I&amp;rsquo;ve planned for a long time.
I wasn&amp;rsquo;t satisfied with my &lt;a href=&#34;https://tic80.com/play?cart=3473&#34; target=&#34;_blank&#34;&gt;existing implementations&lt;/a&gt; of a player controller&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, so I started working on a new one.
After a bit of fiddling around, I came to something I&amp;rsquo;m satisfied with, for now, at least, but while working on it, I wanted to add something I haven&amp;rsquo;t done in any of my projects yet - I decided to add slopes to my game.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m no game developer, to be honest, it&amp;rsquo;s not even my hobby, although I enjoy the process to some extent.
Game development offers immediate visual and interactive feedback, unlike many other areas in programming, and I like that.
So, while working on this player controller and figuring out how to implement slopes, I&amp;rsquo;ve searched the web to see if someone already did something similar in a system I&amp;rsquo;m working with, but I didn&amp;rsquo;t manage to find anything.
Maybe I simply wasn&amp;rsquo;t specific enough in my search requests, or didn&amp;rsquo;t search deep enough, and there&amp;rsquo;s actually a guide on how to do that somewhere on the web, I decided to write this post anyway.&lt;/p&gt;
&lt;h2 id=&#34;aabb-collisions&#34;&gt;AABB collisions&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s discuss what AABB actually means.&lt;/p&gt;
&lt;p&gt;For those unfamiliar with collision detection, there are many ways of checking if two objects collide.
A lot of them, actually, each with its pros and cons.
Some give very accurate collisions for objects of any shape, but are not real-time viable, others are real-time, but far less accurate.
It&amp;rsquo;s an ongoing research, and new ways of detecting complex collisions as fast as possible &lt;a href=&#34;https://www.youtube.com/watch?v=2c8o65JiPQY&amp;amp;pp=ygURb25lIG1pbnV0ZSBwYXBlcnM%3D&#34; target=&#34;_blank&#34;&gt;appear every now and then&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m mainly developing games in either TIC-80 or LÖVE2D.
LÖVE2D actually comes with a collision detection library, called &lt;a href=&#34;https://box2d.org/about/&#34; target=&#34;_blank&#34;&gt;Box2D&lt;/a&gt;.
My games are sprite-based, and since I often use TIC-80, I can&amp;rsquo;t really commit to Box2D, so instead I opt for a simpler collision detection logic.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s where AABB comes - it&amp;rsquo;s an Axis-Sligned Bounding Box collision detection system:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/aabb.png&#34;
         alt=&#34;Figure 1: Axis-aligned rectangles are quite easy to check for intersections, since all we need to know is their origin and dimensions.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Axis-aligned rectangles are quite easy to check for intersections, since all we need to know is their origin and dimensions.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The general idea is that if the bounding box of object A is completely to the left or to the right of object B, the objects don&amp;rsquo;t collide.
Similarly, if the object A is above or below object B, there&amp;rsquo;s no collision either.
And when all four of these situations are not true, then there&amp;rsquo;s a collision.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a rather simple solution, but it can yield satisfying results.
Implementing this by hand is trivial, but there&amp;rsquo;s a lot more to checking collisions - we need to make it quite optimized, and handle object interactions.&lt;/p&gt;
&lt;p&gt;Thankfully, there&amp;rsquo;s an amazing pure Lua library called &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt;, that implements these AABB checks and more.
And it&amp;rsquo;s near perfect for sprite-based games, since everything is aligned to the grid, so that&amp;rsquo;s what I&amp;rsquo;m using in TIC-80 and Love2D.
Perfect, until we want something other than a rectangle.
For example, slopes.&lt;/p&gt;
&lt;h2 id=&#34;implementing-slopes-with-bump-dot-lua&#34;&gt;Implementing slopes with &lt;code&gt;bump.lua&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;To be honest, there&amp;rsquo;s not that much to it for implementing slopes in an AABB collision system.
Actually, I could just give you the formula and be done with it.
Even more, actually - I&amp;rsquo;m sure you can figure it out if you think about it for just a bit.
But that&amp;rsquo;s not fun!
So instead, I&amp;rsquo;ll walk you through from the beginning - creating a TIC project, adding &lt;code&gt;bump.lua&lt;/code&gt;, loading entities to the world, adding collisions, simple physics, and finally, slopes.&lt;/p&gt;
&lt;p&gt;But, if you want, you can skip directly to the &lt;a href=&#34;#implementing-slopes-with-aabb-collisions&#34;&gt;slope implementation section&lt;/a&gt;, no worries!&lt;/p&gt;
&lt;h3 id=&#34;tic-80&#34;&gt;TIC-80&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt; is a small game engine that supports Lua as one of its main languages to develop games, along with other ones, like &lt;a href=&#34;https://fennel-lang.org/&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt;.
I primarily do my projects in Fennel, as I like it a little bit more than Lua&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, but for this post, I chose Lua, as I want this to be a more general tutorial, applicable to a wider audience.&lt;/p&gt;
&lt;p&gt;Even though TIC-80 is a fantasy computer, I believe it is capable of being an engine that you can use to make full-fledged games with.
Two years ago, &lt;a href=&#34;https://www.playbalatro.com/&#34; target=&#34;_blank&#34;&gt;Balatro&lt;/a&gt; again proved that Love2D is fully suited for making massively successful games, without the need for something more, like Godot or Unity.
I think TIC-80 can shine &lt;a href=&#34;https://tic80.com/play?cart=4496&#34; target=&#34;_blank&#34;&gt;similarly&lt;/a&gt;, but it seems that far fewer people consider it as a viable alternative, even fewer than with Love2D.&lt;/p&gt;
&lt;p&gt;The other thing I often think about is that games don&amp;rsquo;t have to be implemented with the best technology to be &lt;em&gt;good games&lt;/em&gt;.
I&amp;rsquo;ve played a few games on Game Boy Color and especially Game Boy Advance, and they were amazing even today.
And these consoles were quite limited even for the time.
Yet, people are still making games for them.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s another reason why I want to write this post more as a tutorial on TIC-80, as it can maybe make you want to try it!&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s start by firing up TIC-80:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/tic80.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;By default, TIC-80 starts you in a console-like environment.
It&amp;rsquo;s a fantasy &lt;em&gt;computer&lt;/em&gt;, after all.&lt;/p&gt;
&lt;p&gt;By pressing &lt;kbd&gt;Esc&lt;/kbd&gt;, you can go into the code editor:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/tic80-code-editor.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can also switch to a built-in sprite editor by pressing &lt;kbd&gt;F2&lt;/kbd&gt; or clicking on a ghost icon in the top bar:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/tic80-sprite-editor.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;There&amp;rsquo;s also a map editor, which we&amp;rsquo;ll look into a bit later, you can create sound effects with a built-in synthesizer and write music in the tracker!
It&amp;rsquo;s a fully self-contained system that you can develop your games in, and not just games - people write music in it, create beautiful &lt;a href=&#34;https://tic80.com/play?cat=5&amp;amp;sort=2&#34; target=&#34;_blank&#34;&gt;entries&lt;/a&gt; for Demo Scene contests, and more.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t be using the inbuilt code editor, though, as I&amp;rsquo;m much more comfortable writing in Emacs, and you can use any external editor with TIC, but we&amp;rsquo;ll be using the sprite and map editors.
So, let&amp;rsquo;s start!&lt;/p&gt;
&lt;h3 id=&#34;creating-a-project-and-adding-bump-dot-lua&#34;&gt;Creating a project and adding &lt;code&gt;bump.lua&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Actually, if you did start the TIC-80 with me, you don&amp;rsquo;t have to create anything - by default, TIC creates a sample cart that you can edit right away.
That&amp;rsquo;s what we&amp;rsquo;ll do.
First, let&amp;rsquo;s edit the metadata at the top of the cart:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- title:   AABB Slopes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- author:  Andrey Listopadov&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- desc:    Making slopes wiht AABB collisions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- site:    https://andreyor.st&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- license: MIT License&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- version: 0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- script:  lua&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We could also delete default sprites right now, but we&amp;rsquo;ll do it later.
Right now, we need to add &lt;code&gt;bump.lua&lt;/code&gt; to the cart.&lt;/p&gt;
&lt;p&gt;TIC-80 doesn&amp;rsquo;t really provide access to your filesystem - it is expected for the cart to contain everything, much like game cartridges did in the early days of home consoles.
Because of that, it&amp;rsquo;s not possible to install &lt;code&gt;bump.lua&lt;/code&gt; via LuaRocks, or download it and place the file near your cart.
We&amp;rsquo;ll have to embed it directly.&lt;/p&gt;
&lt;p&gt;Luckily for us, it&amp;rsquo;s really easy to do so in Lua!
All we need is to set &lt;code&gt;package.preload.bump&lt;/code&gt; to a function that contains &lt;a href=&#34;https://raw.githubusercontent.com/kikito/bump.lua/refs/heads/master/bump.lua&#34; target=&#34;_blank&#34;&gt;all of the library code&lt;/a&gt;.
And even greater, that &lt;code&gt;bump.lua&lt;/code&gt; is a simple, single-file, self-contained Lua library.&lt;/p&gt;
&lt;p&gt;So we can do it like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;package.preload.bump = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- Copy the bump.lua file contens here.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- Yes, as is.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can use &lt;code&gt;require&lt;/code&gt; to bring this library to our game, and create the world:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; bump = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bump&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; world = bump.newWorld(24)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Great! Now let&amp;rsquo;s draw some sprites we&amp;rsquo;ll use!&lt;/p&gt;
&lt;h3 id=&#34;creating-sprites-and-using-the-map-editor&#34;&gt;Creating sprites and using the map editor&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s nothing much to talk about here, as TIC features a rather simplistic sprite editor:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/sprites.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;However, we&amp;rsquo;ll be using some of its advanced features, which can be revealed by pressing this switch in the top left corner of the editor:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/sprites-advanced.png&#34;
         alt=&#34;Figure 2: Advanced mode switch (red arrow), flags (green arrow)&#34; width=&#34;50%&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Advanced mode switch (red arrow), flags (green arrow)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;One of such features is the flags we can set on a sprite.
These flags act as a bit mask, so you can set up to 256 combinations of flags, which is enough, since TIC has space for exactly 256 sprites.
Did I mention how cool the design of TIC is yet?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve set bit 1 here to indicate that this sprite is a ball, and I set bit 0 for all of the solid objects drawn near it.
This way, when we load these sprites to the game world, we&amp;rsquo;ve created with &lt;code&gt;bump.lua&lt;/code&gt;, we will be able determine what this object should be.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s use these sprites in the map editor:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/map-editor.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;In the map editor, you can choose from either 256 tiles or 256 sprites to draw your map with.
TIC actually has two sprite-sets: tiles and sprites.
The only distinction between them is that you&amp;rsquo;re limited to either of those sets when you design your map.
Other than that, they&amp;rsquo;re the same.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve created a small test scene, with our ball and some walls:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/map.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now we can start implementing our game logic, as right now if we run this cart, nothing would happen yet.&lt;/p&gt;
&lt;h3 id=&#34;loading-entities-to-the-world&#34;&gt;Loading entities to the world&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll start by editing the &lt;code&gt;TIC&lt;/code&gt; function in our standard cart:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;TIC&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cls(0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    map(0, 0, 31, 18, 0, 0, 0, 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we run our cart, we&amp;rsquo;ll see the same thing we&amp;rsquo;ve seen in the map editor:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/first-run.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;However, nothing moves yet, as we haven&amp;rsquo;t implemented any of the game&amp;rsquo;s logic.
Before we can do that, we&amp;rsquo;ll need to populate our world with rectangles, so let&amp;rsquo;s do that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;load_map&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; x=0, 240 * 8, 8 &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; y=0, 136 * 8, 8 &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; obj = is_obj(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; obj &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                world:add(obj, obj.x, obj.y, obj.w, obj.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, I&amp;rsquo;m loading the &lt;strong&gt;entire&lt;/strong&gt; map to the world.
It&amp;rsquo;s not necessary to do that, since we&amp;rsquo;re only going to use one map screen, but it doesn&amp;rsquo;t hurt.
The key function here is the &lt;code&gt;is_obj&lt;/code&gt; predicate, which we&amp;rsquo;re going to write next:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; balls = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_obj&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; id = id_at(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; is_solid(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {x = x, y = y, h = 8, w = 8}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; is_ball(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ball = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            x = x,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            y = y,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            h = 8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            w = 8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            xvel = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            yvel = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            is_ball = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        balls[ball] = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ball
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First things first, we need to get the ID of the tile at coordinates &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;.
We do so by using TIC&amp;rsquo;s built-in function &lt;code&gt;mget&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id_at&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; mget(x // 8, y // 8)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we&amp;rsquo;ll define a set of predicates that, given an &lt;code&gt;id&lt;/code&gt; will tell if the object we&amp;rsquo;re inspecting is a wall, or a ball:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_solid&lt;/span&gt;(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; fget(id, 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_ball&lt;/span&gt;(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; fget(id, 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the &lt;code&gt;is_obj&lt;/code&gt; function we&amp;rsquo;ve defined above gets the tile &lt;code&gt;id&lt;/code&gt;, and checks if it is a ball, or a wall tile.
If so, it creates an object that we can add to the &lt;code&gt;bump.lua&lt;/code&gt; world.
Each object has a set amount of required properties, but you can also have additional ones, like the &lt;code&gt;is_ball&lt;/code&gt; field, in the case of the ball object.
We also add a ball to the list of balls, in case we might want to add more than one ball later.&lt;/p&gt;
&lt;p&gt;Now, we can load the map.
We do so in the &lt;code&gt;BOOT&lt;/code&gt; function, which executes when the cart is being loaded.
You can also write the call at the top level if you want, and it may make the code a little bit more portable, as older versions of TIC didn&amp;rsquo;t have &lt;code&gt;BOOT&lt;/code&gt;, but I&amp;rsquo;m not targeting those, so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;BOOT&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    load_map()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that in place, we can implement some simple physics for the ball.&lt;/p&gt;
&lt;h3 id=&#34;working-with-bump-dot-lua&#34;&gt;Working with &lt;code&gt;bump.lua&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Since we&amp;rsquo;ve loaded everything into the world we&amp;rsquo;ve created with &lt;code&gt;bump.lua&lt;/code&gt;, we can now manipulate things in it.
We&amp;rsquo;ll be mainly manipulating balls, so let&amp;rsquo;s add some methods to the &lt;code&gt;balls&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;setmetatable(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    balls,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        __index = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            update = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(self)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; ball &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(self) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.yvel = lerp(ball.yvel, 5, 0.1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.xvel = lerp(ball.xvel, 0, 0.1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.x, ball.y, cols, len = world:move(ball, ball.x + ball.xvel, ball.y + ball.yvel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i = 1, len &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; col = cols[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.y == -1 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            ball.yvel = -(ball.yvel * 0.9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.x ~= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            ball.xvel = -(ball.xvel * 0.9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            draw = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(self)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; ball &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(self) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    spr(1, ball.x, ball.y, 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve added two methods: &lt;code&gt;draw&lt;/code&gt; and &lt;code&gt;update&lt;/code&gt;.
It&amp;rsquo;s not necessary to separate these, you could do everything in one call, but it&amp;rsquo;s a bit easier to reason about them this way.
Yeah, I know, looping over all of the balls two times just to update each, and then draw each is bad design, since we could do it in one loop, but that&amp;rsquo;s not the main focus here.
But it&amp;rsquo;s great that you&amp;rsquo;ve pointed this out!
Ten points to the TIC house!&lt;/p&gt;
&lt;p&gt;Anyway, we&amp;rsquo;re looping over all of the balls in the table, which we don&amp;rsquo;t have that many yet, only one, and updating each one.
The important part here is that we compute the ball&amp;rsquo;s X and Y velocity, and then use them to move the ball in the world, by calling &lt;code&gt;world:move()&lt;/code&gt;.
I&amp;rsquo;m using linear interpolation, defined as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lerp&lt;/span&gt;(a, b, t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ((1 - t) * a) + (t * b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We don&amp;rsquo;t care that much about delta-time here, as TIC runs at a consistent 60 frames per second even when you push it to the limits.
You can, of course, slow it down with bad code, and we already have two loops instead of one, which is concerning, but we&amp;rsquo;ll be fine, don&amp;rsquo;t worry.
Lua is quite fast.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ball.x, ball.y, cols, len = world:move(ball, ball.x + ball.xvel, ball.y + ball.yvel)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So by calling &lt;code&gt;world:move()&lt;/code&gt; with the ball object, we receive new X and Y positions of that ball after it was moved with respect to collisions.
We&amp;rsquo;re not going to build a sophisticated physics engine here, but we will need to handle some collisions.
&lt;code&gt;bump.lua&lt;/code&gt; actually has different &lt;a href=&#34;https://github.com/kikito/bump.lua?tab=readme-ov-file#collision-resolution&#34; target=&#34;_blank&#34;&gt;collision types&lt;/a&gt;, like &lt;code&gt;bounce&lt;/code&gt;, that we could use here, but for our purposes the default &lt;code&gt;slide&lt;/code&gt; is better.&lt;/p&gt;
&lt;p&gt;In addition to the new X and Y positions, this function returns a list of collisions that happened during the move.
We can loop over those and update our ball&amp;rsquo;s properties, such as its velocity.
We do so in the following loop&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i = 1, len &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; col = cols[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.y == -1 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.yvel = -(ball.yvel * 0.9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.x ~= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.xvel = -(ball.xvel * 0.9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re slowly decreasing the ball&amp;rsquo;s velocity, also switching directions on contact.
That&amp;rsquo;s pretty much what the &lt;code&gt;bounce&lt;/code&gt; collision would do for us.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;draw&lt;/code&gt; method, we simply draw the ball sprite using another TIC&amp;rsquo;s builtin function &lt;code&gt;spr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Having these implemented, we can add them to the &lt;code&gt;TIC&lt;/code&gt; function, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;TIC&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cls(0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    map(0, 0, 31, 18, 0, 0, 0, 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    balls:update()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    balls:draw()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we run our game, we&amp;rsquo;ll see our ball bouncing:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/ball-bounce.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Uh oh, why are there two balls, and one floating over the ground?
Did we forget to add it to the &lt;code&gt;balls&lt;/code&gt; table, so it gets updated?
If we did, why is it even drawn - we loop over balls in both functions.&lt;/p&gt;
&lt;p&gt;If you look closer, you&amp;rsquo;ll see the problem.
We&amp;rsquo;ve loaded the map to the world, and we&amp;rsquo;re drawing the ball using the &lt;code&gt;spr&lt;/code&gt; function.
But we&amp;rsquo;re still drawing the original map in the &lt;code&gt;TIC&lt;/code&gt; function by calling &lt;code&gt;map&lt;/code&gt;!
And our map still has the ball.&lt;/p&gt;
&lt;p&gt;We can go two ways here.
One would be to use the &lt;code&gt;mset&lt;/code&gt; function and replace the ball tile with nothing in our map when we&amp;rsquo;re loading it.
Or, we can hide the ball at runtime using &lt;code&gt;map&lt;/code&gt; function&amp;rsquo;s special remapping feature.
Let&amp;rsquo;s do that instead, as it is a bit cleaner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remap&lt;/span&gt;(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; is_ball(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we update our &lt;code&gt;TIC&lt;/code&gt; function to use this &lt;code&gt;remap&lt;/code&gt; function in our &lt;code&gt;map&lt;/code&gt; call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;TIC&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cls(0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    map(0, 0, 31, 18, 0, 0, 0, 1, remap)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    balls:update()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    balls:draw()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, presto!&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/basic-physics.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&#34;handling-mouse-events&#34;&gt;Handling mouse events&lt;/h3&gt;
&lt;p&gt;Our introduction to TIC isn&amp;rsquo;t over yet, because I always wanted to try using the mouse integration.
Our ball is currently pretty stiff, so we&amp;rsquo;ll tweak its physics along the way.
Having mouse support will make it easier to test things out, as doing so by updating the code is a bit cumbersome.
And I don&amp;rsquo;t know how to make sensible controls for a ball with arrow keys - it&amp;rsquo;s just a bouncing ball, what do you expect it to do, roll by itself when you press a magic key??
Let&amp;rsquo;s drag the balls instead.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll start by creating a small storage variable that we&amp;rsquo;ll assign to the currently grabbed ball:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; grabbed = &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s uninitialized by default, we&amp;rsquo;ll set it later in the &lt;code&gt;update&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; mx, my, is_pressed = mouse()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; is_pressed &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;not&lt;/span&gt; grabbed &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; items = world:queryPoint(mx, my, &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(obj) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; obj.is_ball &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; next(items) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        grabbed = items[1]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;not&lt;/span&gt; is_pressed &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; grabbed &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        grabbed.xvel = (grabbed.x - grabbed.prev_x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        grabbed.yvel = (grabbed.y - grabbed.prev_y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        grabbed.prev_x, grabbed.prev_y = &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    grabbed = &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We add this before the main loop over all balls in the &lt;code&gt;update&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mouse&lt;/code&gt; function in TIC returns a set of values, X and Y coordinates, and states of each mouse button.
We&amp;rsquo;re only interested in the left mouse button, so that&amp;rsquo;s what we store.&lt;/p&gt;
&lt;p&gt;Then, if the button is pressed, we use a method from the &lt;a href=&#34;https://github.com/kikito/bump.lua?tab=readme-ov-file#querying-with-a-point&#34; target=&#34;_blank&#34;&gt;Intermediate API&lt;/a&gt; section of &lt;code&gt;bump.lua&lt;/code&gt;.
It returns a list of items, and since we don&amp;rsquo;t have anything that overlaps, we can safely take the first item in the list.
We&amp;rsquo;re also using a similar feature to the &lt;code&gt;map&lt;/code&gt; function&amp;rsquo;s remap here - we&amp;rsquo;re providing a filtering function that will make sure that we can only grab ball objects, not other tiles.&lt;/p&gt;
&lt;p&gt;When the button is released, its state will change, and we need to release the ball.
If there was a ball grabbed, we set its velocity to conserve the momentum from moving it by the mouse, which we&amp;rsquo;ll handle later.
Then we unset the &lt;code&gt;grabbed&lt;/code&gt; storage variable.&lt;/p&gt;
&lt;p&gt;Next, in the &lt;code&gt;for&lt;/code&gt; loop responsible for updating the balls, we check if the current ball is the one we&amp;rsquo;ve grabbed, and we override its movement:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; ball &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(self) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ball == grabbed &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; x, y = lerp(grabbed.x, mx-4, 0.3), lerp(grabbed.y, my-4, 0.3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        grabbed.prev_x, grabbed.prev_y = grabbed.x, grabbed.y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.x, ball.y = world:move(ball, x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- no changes to the old logic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, as you can see, we&amp;rsquo;re moving the ball to the mouse pointer coordinates, still with respect to collisions.
We also store additional information in the &lt;code&gt;grabbed&lt;/code&gt; object, mainly the previous X and Y positions that we use in that momentum conservation code a bit earlier.
And with that, we can drag the ball around:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/mouse-drag.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This is as basic as it gets - you&amp;rsquo;ll notice that if we add more balls, we can&amp;rsquo;t move other balls with the one we&amp;rsquo;re dragging.
You can, of course, make a more sophisticated physics simulation - handle collisions better, so it would move other balls as well, transfer the momentum to other objects, make balls roll off each other, as right now they&amp;rsquo;re basically squares, and so on.&lt;/p&gt;
&lt;p&gt;So you can do something like that if you try experimenting with collision resolution a bit more:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/ball-interactions.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Now, we&amp;rsquo;re pretty much set for working towards the main topic of this post - slopes.&lt;/p&gt;
&lt;h2 id=&#34;implementing-slopes-with-aabb-collisions&#34;&gt;Implementing slopes with AABB collisions&lt;/h2&gt;
&lt;p&gt;Phew, FINALLY, all that just to tell you that to handle slopes you just need to do&amp;hellip;&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/aabb-slope-handling.png&#34;
         alt=&#34;Figure 3: &amp;amp;hellip;is this.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;&amp;hellip;is this.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;OK, this is anticlimactic, so let&amp;rsquo;s implement this.
But first, what is a slope in our case?&lt;/p&gt;
&lt;p&gt;Because we can only have axis-aligned rectangles, we need to create a special kind of object in our world that will still be a rectangle, but handle collisions differently.
Since our game is tile-based, we don&amp;rsquo;t have a lot of meaningful angles to support.
The most common slope in games is a segment with dimensions of &lt;code&gt;16x8&lt;/code&gt;.
It spans exactly two tiles and takes you one tile height up.
Let&amp;rsquo;s draw it:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/slope-sprites.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can see that I&amp;rsquo;ve set bit 2 to the slope tile here, so we can correctly handle it while loading our map to the world.
If we add these to the world right now, they won&amp;rsquo;t work, obviously, since these are regular rectangles:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/slopes-dont-work-yet.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s change that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_up_slope&lt;/span&gt;(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; fget(id, 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_down_slope&lt;/span&gt;(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; fget(id, 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ll start by defining two more predicates, and then use them in our &lt;code&gt;is_obj&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_obj&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; id = id_at(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; is_solid(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {x = x, y = y, h = 8, w = 8}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; is_up_slope(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {x = x, y = y, h = 8, w = 16, slope = slope, dir = 1}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; is_down_slope(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {x = x, y = y, h = 8, w = 16, slope = slope, dir = -1}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; is_ball(id) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ball = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            x = x,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            y = y,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            h = 8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            w = 8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            xvel = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            yvel = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            is_ball = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        balls[ball] = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ball
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, these are regular rectangles, except in our world, the &lt;code&gt;8x8&lt;/code&gt; tile creates a &lt;code&gt;16x8&lt;/code&gt; rectangle.
The other half of the slope is just decoration.&lt;/p&gt;
&lt;p&gt;We also have the &lt;code&gt;slope&lt;/code&gt; and &lt;code&gt;dir&lt;/code&gt; fields here.
The &lt;code&gt;slope&lt;/code&gt; is a function responsible for handling collisions that we&amp;rsquo;ll implement shortly.
The &lt;code&gt;dir&lt;/code&gt; field determines if this is an up-slope, raising from left to right, or a down-slope, lowering from left to right (or raising from right to left).
We need to know the direction, otherwise, we won&amp;rsquo;t be able to calculate normals and properly map coordinates to new values.&lt;/p&gt;
&lt;h3 id=&#34;calculating-slope-collision-coordinates&#34;&gt;Calculating slope collision coordinates&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;slope&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope&lt;/span&gt;(obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; obj.yvel &amp;gt;= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; _, _, cols, len = world:check(obj, obj.x, obj.y + obj.yvel, slope_filter)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i=1, len &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; col = cols[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.y ~= 1 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- -1 or 0 will do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; slope_floor = col.other.y - col.other.h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; delta = clamp(0, (obj.x + obj.w / 2) - col.other.x, col.other.w) / col.other.w
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; y_off = &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.other.dir &amp;gt; 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    y_off = lerp(col.other.h, 0, delta)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    y_off = lerp(0, col.other.h, delta)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; newy = slope_floor + y_off
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; math.floor(newy), slope_normal(col.other)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, that&amp;rsquo;s a lot to take in.
Let&amp;rsquo;s go through step by step.&lt;/p&gt;
&lt;p&gt;First, we check if the object&amp;rsquo;s velocity is going at least downwards.
We don&amp;rsquo;t want to trigger slope collisions when objects move away from the slope, so that&amp;rsquo;s pretty simple.&lt;/p&gt;
&lt;p&gt;Next, as usual, we need to handle collisions.
However, there&amp;rsquo;s a catch - since our slopes are rectangles in disguise, we can&amp;rsquo;t just use the normal &lt;code&gt;world:move()&lt;/code&gt; and be done.
Instead, we need to kinda implement the &lt;code&gt;world:move()&lt;/code&gt; in terms of &lt;code&gt;world:check()&lt;/code&gt; and &lt;code&gt;world:update()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;check&lt;/code&gt; method does the same stuff as &lt;code&gt;move&lt;/code&gt; except it doesn&amp;rsquo;t move anything.
It pretends that the object has moved, and returns a list of collisions and coordinates where it would end up if it actually moved.
That&amp;rsquo;s perfect for our needs.
The &lt;code&gt;update&lt;/code&gt; method can move the object around without checking for any collisions, and that&amp;rsquo;s the other piece of the puzzle.&lt;/p&gt;
&lt;p&gt;But right now, the ball collides with the slope rectangle, and it can&amp;rsquo;t go further, what can we do?
We use filtering, of course.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;world:check()&lt;/code&gt; also accepts the collision filter, as &lt;code&gt;world:move()&lt;/code&gt; does.
We&amp;rsquo;ll need to add two new filter functions, one for checking slopes specifically, and the other to allow balls to move through slope rectangles freely:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slope_filter&lt;/span&gt;(_, other)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; other.slope &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;cross&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball_filter&lt;/span&gt;(_, other)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; other.slope &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;cross&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;slide&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that out of the way, we can go into collision checking.&lt;/p&gt;
&lt;p&gt;As usual, we iterate over a list of collisions.
We then check if the collision&amp;rsquo;s Y component of the normal vector points at least up.
If so, we have our collision, but we are just getting started.&lt;/p&gt;
&lt;p&gt;Next, we calculate the slope floor Y position.
This is the lowest coordinate our collision could possibly have:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; slope_floor = col.other.y - col.other.h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we calculate the delta:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; delta = clamp(0, (obj.x + obj.w / 2) - col.other.x, col.other.w) / col.other.w
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is how far from the left edge of the slope rectangle the collision is going to happen.
We try to measure in the center of the colliding tile, and normalize it to be a value from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, we need to determine the Y coordinate on that slope:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; y_off = &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.other.dir &amp;gt; 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    y_off = lerp(col.other.h, 0, delta)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    y_off = lerp(0, col.other.h, delta)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We do so by checking the slope direction, and do a linear interpolation between &lt;code&gt;0&lt;/code&gt; and slope height, using our delta value.
Linear interpolation will move us in a straight diagonal line from the bottom corner of the slope to the top corner of the slope.
Direction is simply used to flip the interpolation.&lt;/p&gt;
&lt;p&gt;Finally, we&amp;rsquo;re calculating a ney Y position, and normals to return:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; newy = slope_floor + y_off
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; math.floor(newy), slope_normal(col.other)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Our Y position from &lt;code&gt;lerp&lt;/code&gt; is relative to the slope, so we add back the &lt;code&gt;slope_floor&lt;/code&gt; position to translate it back to world coordinates.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s pretty much just a small part of it!
Wait&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;handling-slope-collisions&#34;&gt;Handling slope collisions&lt;/h3&gt;
&lt;p&gt;We still need to adjust the object&amp;rsquo;s position to that coordinate - why didn&amp;rsquo;t we do so in the slope function itself?
Well, because reasons&amp;hellip;&lt;/p&gt;
&lt;p&gt;I mean, I tried to do that, but it didn&amp;rsquo;t work well, there are many outside factors that we may need to consider, and it&amp;rsquo;s not the best way to move it to this function.
So let&amp;rsquo;s change our &lt;code&gt;update&lt;/code&gt; method of the &lt;code&gt;balls&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s handle normal ball collisions.
Mouse collisions will come later:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; ball &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(self) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ball == grabbed &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;--- 8&amp;lt; ---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.yvel = lerp(ball.yvel, 5, 0.075)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.xvel = lerp(ball.xvel, 0, 0.03)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.x, ball.y, cols, len = world:move(ball, ball.x + ball.xvel, ball.y + ball.yvel, ball_filter)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i = 1, len &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; col = cols[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.other.slope &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; newy, xnorm, ynorm = col.other.slope(ball)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; newy &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; ball.y &amp;gt;= newy &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    world:update(ball, ball.x, newy, ball.w, ball.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.y = newy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.xvel = ball.xvel + xnorm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.yvel = (- ball.yvel - ynorm) * 0.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.y ~= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.yvel = -(ball.yvel * 0.9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.xvel = ball.xvel * 0.75
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.normal.x ~= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.xvel = -(ball.xvel * 0.9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  Imagine if I didn&#39;t stack the &lt;code&gt;end&lt;/code&gt; keywords on the same line? This post would be even longer! It&#39;s already a bit too long&amp;#x2026;
&lt;/div&gt;
&lt;p&gt;Main differences from before: we added &lt;code&gt;ball_filter&lt;/code&gt; to the &lt;code&gt;world:move()&lt;/code&gt; call, and split collision handling logic into two separate branches.
The first branch checks if the collision happens with a slope and handles it.
The second branch is the same as before.&lt;/p&gt;
&lt;p&gt;The collision handling is pretty simple, really - we check if &lt;code&gt;slope&lt;/code&gt; actually returned a new coordinate, and if the ball&amp;rsquo;s current Y position is lower than that, we need to handle the collision.
The &lt;code&gt;ball_filter&lt;/code&gt; sets slope collisions to &lt;code&gt;cross&lt;/code&gt;, and it allows balls to move through slope blocks as if they&amp;rsquo;re not there, except we still get collision information.
So if the ball&amp;rsquo;s Y coordinate is less than the slope collision coordinate, it means that we need to push the ball out of the slope.
We do it straight up, without concerns about the normal vector to the slope, but it is possible to do so (I&amp;rsquo;m just lazy).&lt;/p&gt;
&lt;p&gt;Calling &lt;code&gt;world:update()&lt;/code&gt; sets the ball to a new position, and we also update its fields to set the new coordinate, and update velocities.
We also break from this loop, as we don&amp;rsquo;t really want to handle any other collision, since it could get messy.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s do the same for mouse movement:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; ball &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(self) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ball == grabbed &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; x, y = lerp(ball.x, mx-4, 0.3), lerp(ball.y, my-4, 0.3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.prev_x, ball.prev_y = ball.x, ball.y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ball.x, ball.y, cols, len = world:move(ball, x, y, ball_filter)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i = 1, len &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; col = cols[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; col.other.slope &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; yvel = ball.yvel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ball.yvel = 1 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- needed for the slope check to happen&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; newy = col.other.slope(ball)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ball.yvel = yvel &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- restore the original velocity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; newy &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; ball.y &amp;gt;= newy &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    world:update(ball, ball.x, newy, ball.w, ball.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    ball.y = newy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;--- 8&amp;lt; ---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s pretty similar to the one above, except we need to do a small trick.&lt;/p&gt;
&lt;p&gt;Notice how we set the ball&amp;rsquo;s velocity to &lt;code&gt;1&lt;/code&gt; right before the check?
Since the ball is moved by the mouse, its velocity is not really updated.
Don&amp;rsquo;t ask me how long I was debugging why the collision doesn&amp;rsquo;t happen&amp;hellip;&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s pretty much it!&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/slopes-work.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We can also add a different kind of slope to show that this approach is generic enough:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/more-slopes.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is still, by no means, a proper physics simulation of slopes.
Balls bounce off slopes in the wrong direction at certain angles, normals are ignored when handling collisions, but hey, this might not be a problem in your game at all!&lt;/p&gt;
&lt;p&gt;For instance, in my original case, the player is the main object I need to be able to interact with slopes, and I have a pretty simplistic game-oriented physics.
So I don&amp;rsquo;t need the player to jump in a weird way when it&amp;rsquo;s on a slope - jumps should remain predictable.
There are no projectiles that bounce off walls either, and thus, this implementation works fine.&lt;/p&gt;
&lt;p&gt;You can, of course, use these principles to implement a more sophisticated engine.
And there&amp;rsquo;s still a lot of room for improvement, too.&lt;/p&gt;
&lt;p&gt;For instance, the way we define slopes is quite limited.
Sure, we can adjust the slope angle, but because we&amp;rsquo;re building large slopes from small building blocks, there&amp;rsquo;s a wonky collision at these blocks&amp;rsquo; corners.
Instead, we could define two points and programmatically generate map tiles along the slope angle up to its end, using predefined sprites.
And for non-sprite-based games, it doesn&amp;rsquo;t make sense to limit slopes to certain angles - you can define arbitrary-sized rectangles, making slopes as steep as needed.&lt;/p&gt;
&lt;p&gt;Alternatively, you can refactor this code and define slopes as mathematical functions.
Thus, you&amp;rsquo;ll be able to create splines and have curved slopes.
Normal vector calculation will be a bit tougher, though.&lt;/p&gt;
&lt;p&gt;And actually, if you happen to know some blog posts on the matter, please send them!
I&amp;rsquo;m quite interested.&lt;/p&gt;
&lt;p&gt;If you want to experiment with the code, here&amp;rsquo;s a cart that you can load with TIC-80, or you can &lt;a href=&#34;https://tic80.com/play?cart=4497&#34; target=&#34;_blank&#34;&gt;experiment online&lt;/a&gt; on TIC&amp;rsquo;s website:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2026-01-09-slopes-in-aabb-collision-systems/aabb-slopes.png&#34;
         alt=&#34;Figure 4: That&amp;amp;rsquo;s an actual game cartridge you can load into TIC-80!&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;That&amp;rsquo;s an actual game cartridge you can load into TIC-80!&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;That&amp;rsquo;s all from me.
Hope you&amp;rsquo;ve enjoyed this write-up as much as I did, and see you next time!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Code responsible for controlling the player object - movement, abilities, general game logic&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Fennel &lt;strong&gt;is&lt;/strong&gt; Lua, but it adds a few features on top, like macros that allow additional metaprogramming capabilities, and fixes a bunch of Lua&amp;rsquo;s shortcomings.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;This looks so much tighter in Fennel, gosh:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cols&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.y&lt;/span&gt; -1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball.yvel&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball.yvel&lt;/span&gt; 0.9))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col.normal.x&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball.xvel&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball.xvel&lt;/span&gt; 0.9)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Slopes in AABB collision systems&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 09 Jan 2026 04:11:00 +0300</pubDate>
    </item><item>
      <title>2025 Recap</title>
      <link>https://andreyor.st/posts/2025-12-28-2025-recap/</link>
      <guid>https://andreyor.st/posts/2025-12-28-2025-recap/</guid>
      <description>&lt;p&gt;This sure was a long year.&lt;/p&gt;
&lt;h2 id=&#34;work-stuff&#34;&gt;Work stuff&lt;/h2&gt;
&lt;p&gt;January began with bad news - the product I worked on was about to be closed.
We weren&amp;rsquo;t sure how things would go, and a lot of people started to worry about their job security.
And rightfully so, a few months later, the decision was made to reduce staff, and our team was on the list.
A lot of people got laid off, only a few remain to support the project in a dormant state.&lt;/p&gt;
&lt;p&gt;I was transferred to a different project, thankfully, but the company I was working for experienced a lot of management-related issues and transformations, so ultimately, I decided to leave this company in July.
Not that I&amp;rsquo;m complaining, though, I worked there for five whole years, and was thinking about it for some time already - the events just motivated me to do so.
I think five years is a lot of time, and I&amp;rsquo;ve achieved enough and learned a lot during that time.
It was still kinda sad to leave, as there are still a lot of amazing people working there, but I needed a change.&lt;/p&gt;
&lt;p&gt;So now I&amp;rsquo;m working at Health Samurai!
Happy to continue my growth as a Clojure developer, and tap into other technologies I wasn&amp;rsquo;t able to on my previous job.&lt;/p&gt;
&lt;h2 id=&#34;music&#34;&gt;Music&lt;/h2&gt;
&lt;p&gt;In March, I released my very first original music:&lt;/p&gt;
&lt;div class=&#34;yt_container&#34;&gt;
  &lt;iframe width=&#34;560&#34;
          height=&#34;315&#34;
          src=&#34;https://www.youtube.com/embed/PLjwLPNKatc&#34;
          title=&#34;YouTube video player&#34;
          frameborder=&#34;0&#34;
          allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34;
          referrerpolicy=&#34;strict-origin-when-cross-origin&#34;
          allowfullscreen&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I have never written music before, and I don&amp;rsquo;t have any musical training (besides two months in a music school when I was about ten years old), so I&amp;rsquo;m excited to dive deeper into this art field.
I&amp;rsquo;ve also recorded two more covers.&lt;/p&gt;
&lt;p&gt;Vicarious by TOOL:&lt;/p&gt;
&lt;div class=&#34;yt_container&#34;&gt;
  &lt;iframe width=&#34;560&#34;
          height=&#34;315&#34;
          src=&#34;https://www.youtube.com/embed/I21vzo-bmH8&#34;
          title=&#34;YouTube video player&#34;
          frameborder=&#34;0&#34;
          allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34;
          referrerpolicy=&#34;strict-origin-when-cross-origin&#34;
          allowfullscreen&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;CRAWL by VELTPUNCH:&lt;/p&gt;
&lt;div class=&#34;yt_container&#34;&gt;
  &lt;iframe width=&#34;560&#34;
          height=&#34;315&#34;
          src=&#34;https://www.youtube.com/embed/hL9QbWHD_KM&#34;
          title=&#34;YouTube video player&#34;
          frameborder=&#34;0&#34;
          allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34;
          referrerpolicy=&#34;strict-origin-when-cross-origin&#34;
          allowfullscreen&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Looking back, I think my music output this year wasn&amp;rsquo;t really that great - only three recordings, compared to five in 2024, but I was busy most of the time.
Still a lot more than in 2023 (zero output that year, and any year before 2024 to be honest).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve pretty much completed my pedalboard setup and started using it in place of digital effects when recording.
This somewhat limits my sound, compared to the endless variety of effects available in the DAW, but I like to work with limitations.
Here&amp;rsquo;s a video on that:&lt;/p&gt;
&lt;div class=&#34;yt_container&#34;&gt;
  &lt;iframe width=&#34;560&#34;
          height=&#34;315&#34;
          src=&#34;https://www.youtube.com/embed/APK7ITQhTo4&#34;
          title=&#34;YouTube video player&#34;
          frameborder=&#34;0&#34;
          allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34;
          referrerpolicy=&#34;strict-origin-when-cross-origin&#34;
          allowfullscreen&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&#34;gaming&#34;&gt;Gaming&lt;/h2&gt;
&lt;p&gt;I got a Game Boy Advance as a birthday gift this year!
I have a vivid memory, how one of my classmates back in 2003 said that I&amp;rsquo;ll never get one - &lt;a href=&#34;https://www.youtube.com/watch?v=6FwmGLzyRDk&#34; target=&#34;_blank&#34;&gt;well well well, how the turntables&amp;hellip;&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Played and completed on GBA:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kirby: Nightmare in the Dream Land&lt;/li&gt;
&lt;li&gt;Kirby and the Amazing Mirror&lt;/li&gt;
&lt;li&gt;Rayman Advance&lt;/li&gt;
&lt;li&gt;Final Fantasy VI (in progress)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyhow, I like retro gaming - I&amp;rsquo;ve played a bunch of games on my 3DS in the past, and they were great.
Now I can play even older games, and let me tell you - playing them on original hardware is a &lt;em&gt;completely&lt;/em&gt; different experience.
Stripped of the convenience of emulation, like save-states and ergonomic controllers, these games do feel different.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also thinking about trying game development for GBA.
No plans on this yet, but this style and format of games is probably my favorite.&lt;/p&gt;
&lt;p&gt;This year, I also played a lot of Switch games, namely Tunic, Moonscars, World of Goo 2, Dark Souls, Astral Chain, completed Kirby and the Forgotten Land with my now fiancée, and the Crypt of the Necrodancer.
Also played Fire Emblem: Awakening and Super Mario World on my 3DS.
Tunic is probably my game of the year this time, it&amp;rsquo;s purely amazing.&lt;/p&gt;
&lt;h2 id=&#34;new-hobbies&#34;&gt;New hobbies&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve always said that programming is my hobby.
However, this year was weird - I had almost no output as a programmer outside of my day job.&lt;/p&gt;
&lt;p&gt;Sure, I worked on &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;deps.fnl&lt;/a&gt; a bit, but that&amp;rsquo;s it.
Looking at the list of published posts, the only other programming-related ones are about &lt;a href=&#34;https://andreyor.st/posts/2025-06-09-implementing-dynamic-scope-for-fennel-and-lua/&#34;&gt;fennel-mode&lt;/a&gt; and &lt;a href=&#34;https://andreyor.st/posts/2025-04-07-string-interpolation-in-lua/&#34;&gt;string interpolation in Lua&lt;/a&gt;.
Most of the others are just random thoughts and yapping.&lt;/p&gt;
&lt;p&gt;Well, music is my other hobby, but I already talked about it here.&lt;/p&gt;
&lt;p&gt;However, this year was interesting in that I started attending various workshops.
Last year I tried forging, this year I tried pottery, mosaic, and Tiffany glass making:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-28-2025-recap/plate.jpg&#34;
         alt=&#34;Figure 1: Flourless panCakes. Text says: &amp;amp;ldquo;Pancakes without damn flour is an omelette.&amp;amp;rdquo;&#34; width=&#34;35%&#34; height=&#34;auto&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Flourless panCakes. Text says: &amp;ldquo;Pancakes without damn flour is an omelette.&amp;rdquo;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-28-2025-recap/mosaica.jpg&#34;
         alt=&#34;Figure 2: The goose is made by me, and the kitty is made by my fiancée&#34; width=&#34;50%&#34; height=&#34;auto&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;The goose is made by me, and the kitty is made by my fiancée&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-28-2025-recap/pottery.jpg&#34;
         alt=&#34;Figure 3: I&amp;amp;rsquo;ve tried to make a tall Japanese-like teacup. My fiancée made a small bowl&#34; width=&#34;50%&#34; height=&#34;auto&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;I&amp;rsquo;ve tried to make a tall Japanese-like teacup. My fiancée made a small bowl&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-28-2025-recap/tiffany.jpg&#34;
         alt=&#34;Figure 4: Tiffany glass. Mine on the right side, my fiancée&amp;amp;rsquo;s on the left&#34; width=&#34;35%&#34; height=&#34;auto&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;Tiffany glass. Mine on the right side, my fiancée&amp;rsquo;s on the left&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I hope to see myself attending more such workshops in the next year!&lt;/p&gt;
&lt;h2 id=&#34;trips&#34;&gt;Trips&lt;/h2&gt;
&lt;p&gt;Managed to take two trips this year.
One to Thailand at the start of the year, and one to Dubai this month.&lt;/p&gt;
&lt;p&gt;Both trips went smoothly, although we were fearing that we would have trouble leaving Dubai, because a flood occurred a day before our flight.
But we&amp;rsquo;ve managed to fly back home with no major issues.&lt;/p&gt;
&lt;p&gt;Thailand was fun, since it&amp;rsquo;s a first trip in a long time where we flew as a company of four people, and accidentally met a few more people who were in Thailand at the same time, as a pure coincidence.
We&amp;rsquo;ve rented a car and gone to different places on our own.
It was a blast.&lt;/p&gt;
&lt;p&gt;My usual vacation routine is: sleep, eat, swim, eat, swim, eat, sleep.
After seven days or so, I begin to feel extremely bored, so I start to want to return home.
This Dubai trip was not like that at all.
It&amp;rsquo;s already a bit too cold to swim in December, so instead we were going to different places, similar to how we did in Thailand.&lt;/p&gt;
&lt;p&gt;Dubai is an interesting country.
They have a lot of money and ambition, and manage to pull off a lot of interesting ideas regarding their infrastructure.
Sadly, not all is great, as mentioned, there are occasional floods when heavy rain comes, rooftops are leaking, and traffic jams are a major problem even when it&amp;rsquo;s not raining.
The weather is nice, the sites are amazing, and it was, in general, an interesting experience to visit a country with such high ambitions.
The feats they managed to pull off with the construction of their human-made islands are nothing but astonishing.&lt;/p&gt;
&lt;h2 id=&#34;plans-for-2026&#34;&gt;Plans for 2026&lt;/h2&gt;
&lt;p&gt;I plan to continue my music journey, already have a few more covers planned, so stay tuned!
I also want to write more original music, so I&amp;rsquo;m looking forward to experimenting with it.&lt;/p&gt;
&lt;p&gt;As for this blog - I&amp;rsquo;m not really sure.
Each year, as it seems, I have less and less to write about here.&lt;/p&gt;
&lt;p&gt;This year was particularly slow for me because I didn&amp;rsquo;t work on that many projects, and thus, I don&amp;rsquo;t have any material to write about.
I don&amp;rsquo;t see this as a problem, though - this blog is mainly for collecting my thoughts, and since I don&amp;rsquo;t have that many right now, I&amp;rsquo;m not feeling like forcing myself.
However, if this trend continues, I may stop paying for my own domain and go back to using the GitLab pages domain directly.
No concrete thoughts on this yet, but maybe something like that would happen eventually.&lt;/p&gt;
&lt;p&gt;As for long-term projects, I continue experimenting with Fennel and Lua, so maybe there will be more posts on these topics.
Currently, I&amp;rsquo;m trying to work out a better model for immutable tables in Lua, given that my current implementation has poor performance characteristics.
Maybe, I&amp;rsquo;ll rework my fennel-cljlib project to be a bit more robust.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all from me, I wish you a happy new year, and hope to see you here in 2026!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: 2025 Recap&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 28 Dec 2025 12:28:00 +0300</pubDate>
    </item><item>
      <title>MacOS Music Players</title>
      <link>https://andreyor.st/posts/2025-12-10-macos-music-players/</link>
      <guid>https://andreyor.st/posts/2025-12-10-macos-music-players/</guid>
      <description>&lt;p&gt;A sequel to &lt;a href=&#34;https://andreyor.st/posts/2023-11-19-linux-music-players/&#34;&gt;Linux Music Players&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using Linux for the past 15 years and managed to solve almost all my problems with it during that time.
But I had to switch to a Mac due to reasons related both to my work and my hobbies, so now I have to solve the same kind of problems, but in macOS.&lt;/p&gt;
&lt;p&gt;I like music.
No, I &lt;strong&gt;love&lt;/strong&gt; music.&lt;/p&gt;
&lt;p&gt;Maybe I&amp;rsquo;m not the biggest music listener in the world, and my tastes and music knowledge may seem quite limited. For someone who listens to almost everything, I still think that I love music.
I enjoy listening to albums in many genres, but with all honesty, I don&amp;rsquo;t really research anything about people behind the music I&amp;rsquo;m listening to.
This backfired at me a few times when I was interested in the artist, and after reading about them made me a lot less into their music.
So I try to avoid this.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s beside the point.
The main aim of this post is again to compare various music players, but now for macOS.
Since I don&amp;rsquo;t want to use two laptops at once, just to listen to music from the other one, I had to find a suitable alternative to my Linux music player of choice: Strawberry.&lt;/p&gt;
&lt;p&gt;Since the previous post, I&amp;rsquo;ve pretty much settled on Strawberry and have been using it since.
After a bit of tuning, the user experience is at least tolerable, and I was able to stop thinking about it much after I got accustomed to the way you&amp;rsquo;re supposed to interact with your music library.&lt;/p&gt;
&lt;h2 id=&#34;strawberry&#34;&gt;&lt;a href=&#34;https://www.strawberrymusicplayer.org/&#34; target=&#34;_blank&#34;&gt;Strawberry&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/strawberry.png&#34;
         alt=&#34;Figure 1: Strawberry screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Strawberry screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;So let&amp;rsquo;s start with Strawberry.
Unfortunately, Strawberry isn&amp;rsquo;t available on macOS, at least not through brew - the search for &amp;ldquo;strawberry&amp;rdquo; on brew points to a browser named &amp;ldquo;Strawberry&amp;rdquo;.
I was looking into Strawberry&amp;rsquo;s GitHub page, but there&amp;rsquo;s no release artifact for macOS.
Their official webpage has a link to macOS release, but it is behind a paywall.
And I would gladly pay for it, but unfortunately, I can&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Clementine, which is what strawberry was forked from, is &lt;a href=&#34;https://formulae.brew.sh/cask/clementine#default&#34; target=&#34;_blank&#34;&gt;available&lt;/a&gt; through brew, but it is marked as &amp;ldquo;disabled&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;audacious&#34;&gt;&lt;a href=&#34;https://audacious-media-player.org/&#34; target=&#34;_blank&#34;&gt;Audacious&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/audacious.png&#34;
         alt=&#34;Figure 2: Audacious screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Audacious screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve tried Audacious before.
It&amp;rsquo;s a neat little player, but I feel like I&amp;rsquo;m a bit too dumb to use it.&lt;/p&gt;
&lt;p&gt;Again, I don&amp;rsquo;t really like playlists.
I said this before, I say it again.
So music players that are designed around playlists are not my cup of tea.&lt;/p&gt;
&lt;p&gt;I understand that an album is essentially a playlist, but it&amp;rsquo;s so clumsy.&lt;/p&gt;
&lt;p&gt;But I feel like repeating myself, so let&amp;rsquo;s look at some music players I didn&amp;rsquo;t talk about before.&lt;/p&gt;
&lt;h2 id=&#34;cog&#34;&gt;&lt;a href=&#34;https://cog.losno.co/&#34; target=&#34;_blank&#34;&gt;Cog&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-10-macos-music-players/cog.png&#34;
         alt=&#34;Figure 3: Cog screenshot from the project GitHub repo&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Cog screenshot from the project GitHub repo&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;OK, so Cog is the first &lt;em&gt;native&lt;/em&gt; macOS music player that I&amp;rsquo;ll talk about today.
By native, I mean that this is not a Linux application running on macOS - instead it&amp;rsquo;s built for macOS specifically.
I have my thoughts on this, mainly - if I like some os-specific software, and in some years I&amp;rsquo;ll have to switch from macOS, it&amp;rsquo;ll be a shame if I won&amp;rsquo;t be able to use it.
So I tend to avoid stuff that is not cross-platform.
Yes, there are benefits for supporting a single platform, don&amp;rsquo;t get me wrong, that&amp;rsquo;s just how I lived for the past 15 years.&lt;/p&gt;
&lt;p&gt;So, Cog.
It&amp;rsquo;s a nice music player.&lt;/p&gt;
&lt;p&gt;Again, playlist-oriented.
Not my cup of tea, but I can work with that in the absence of alternatives.&lt;/p&gt;
&lt;p&gt;Unlike Audacious, Cog has a library tree, like Strawberry did.
This is good, because I can just click on an album in the tree and listen to it.
I would prefer if albums were represented as a grid, with beautiful album covers and the ability to group them by artist, but again, that&amp;rsquo;s for some reason not really popular in most standalone music players.
Maybe I&amp;rsquo;m crazy to want this, but so few music players do that that I wonder if I&amp;rsquo;m in the wrong.
At least, I can organize my library as a tree of directories, and the player doesn&amp;rsquo;t get in the way.&lt;/p&gt;
&lt;p&gt;One thing that bothers me is that there seems to be some problem with detecting track numbers from the metadata.
More often than not, tracks are ordered the same way files in the directory are.
This is not bad - if anything it&amp;rsquo;s even better, as with this the file system fully controls the library structure.
The problem is, not all of my library is that well organized, although I try to update it if I find these kinds of problems.
And the library search could be better.&lt;/p&gt;
&lt;p&gt;Another small hiccup is that there&amp;rsquo;s no integration with Lastfm.
I&amp;rsquo;m not the biggest scrobbler, but I try to do so, and Strawberry was able to do that.&lt;/p&gt;
&lt;h2 id=&#34;music&#34;&gt;Music&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-10-macos-music-players/music.png&#34;
         alt=&#34;Figure 4: Music screenshot from the guide page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;Music screenshot from the &lt;a href=&#34;https://support.apple.com/guide/music/welcome/mac&#34; target=&#34;_blank&#34;&gt;guide page&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The inbuilt music player.&lt;/p&gt;
&lt;p&gt;Looking at the screenshot you can see that it has a grid of albums, I&amp;rsquo;ve talked about in the previous section on Cog.
Good, right?
I finally found it!&lt;/p&gt;
&lt;p&gt;Well, no.
This app sucks.&lt;/p&gt;
&lt;p&gt;First of all, it doesn&amp;rsquo;t play FLAC, even though macOS can play FLAC files with the Preview program.
So not having support for it in the default music player is bonkers.&lt;/p&gt;
&lt;p&gt;Secondly, it&amp;rsquo;s really weird in how it treats your music library.
I&amp;rsquo;ve mentioned how Cog, and most other music players for that matter, read your library from a directory and can use the directory structure to organize the library.
Music app doesn&amp;rsquo;t do that.
Instead, it organizes your library via file tags.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m having my library backed up on an external drive, so I don&amp;rsquo;t want a music player to touch my directory structure in any way.
So using Music is out of the question.&lt;/p&gt;
&lt;h2 id=&#34;vlc&#34;&gt;&lt;a href=&#34;https://www.videolan.org/vlc/&#34; target=&#34;_blank&#34;&gt;VLC&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-10-macos-music-players/vlc.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;VLC is one of the greatest things that happened in free software.
It&amp;rsquo;s mainly a video player, but it actually plays music just fine too.
Can&amp;rsquo;t say that this is a music player with a good user experience though.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried VLC many times, and every time I couldn&amp;rsquo;t wrap my head around the UX.
There were always some weird things.&lt;/p&gt;
&lt;p&gt;For example, when I open VLC and navigate to my music library, it is presented as a tree view.
However, there&amp;rsquo;s no way to expand a single node of that tree - you can either expand all, or double-click on it, and start playing.
It plays the first album it finds, and it&amp;rsquo;s not what I usually want.
Maybe that&amp;rsquo;s a bug, but what can I say?&lt;/p&gt;
&lt;p&gt;On Android, for example, VLC is quite different - it has a grid view with albums, so I wonder why the desktop version doesn&amp;rsquo;t have that.&lt;/p&gt;
&lt;h2 id=&#34;mpv&#34;&gt;&lt;a href=&#34;https://mpv.io/&#34; target=&#34;_blank&#34;&gt;MPV&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-10-macos-music-players/mpv.png&#34;
         alt=&#34;Figure 5: MPC screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;MPC screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Another video player.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve used MPV as a music player for a long time in my Linux days, before finally switching to Strawberry.
It does the job - you just drag a folder into its main window, and it plays the thing.&lt;/p&gt;
&lt;p&gt;Minimal UI, basic controls, and good sound.
What more can I ask for?&lt;/p&gt;
&lt;p&gt;Well, less minimal UI would be nice.&lt;/p&gt;
&lt;p&gt;I was considering using it, but after using a proper music player for some time, I don&amp;rsquo;t want to go back.
It&amp;rsquo;s a hassle to open Finder, navigate to the library, then open MPV and drag a folder there.&lt;/p&gt;
&lt;h2 id=&#34;museeks&#34;&gt;&lt;a href=&#34;https://github.com/martpie/museeks&#34; target=&#34;_blank&#34;&gt;Museeks&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-12-10-macos-music-players/museeks.png&#34;
         alt=&#34;Figure 6: Museeks screenshot from the project GitHub repo&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;Museeks screenshot from the project GitHub repo&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Like Cog, this player is playlist-oriented, but it also has an album view, although not as a grid, but as a list.
I liked it, but it doesn&amp;rsquo;t have any settings presented to the user, as it seems, or at least I couldn&amp;rsquo;t find the settings.&lt;/p&gt;
&lt;p&gt;Unfortunately, it didn&amp;rsquo;t manage to import all of my library.
A lot of albums are missing in the album view, and it seems that there are issues with support for CUE files.
Seriously, why is it so hard to support CUE?
I&amp;rsquo;ve talked about it in my previous post on the matter, and it&amp;rsquo;s wild that this continues here.&lt;/p&gt;
&lt;h2 id=&#34;others&#34;&gt;Others&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll go over some more music players that I tried, or tried to try but couldn&amp;rsquo;t.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.5kplayer.com/&#34; target=&#34;_blank&#34;&gt;5K Player&lt;/a&gt; - initially was scared off by its webpage, but tried it through brew. Didn&amp;rsquo;t like it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://flavio.tordini.org/musique&#34; target=&#34;_blank&#34;&gt;Musique&lt;/a&gt; - not available through brew, and I can&amp;rsquo;t install it from the App Store.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://vox.rocks/mac-music-player/&#34; target=&#34;_blank&#34;&gt;Vox&lt;/a&gt; - Paid subscription, playlist-oriented, audiophile-oriented. Not my cup of tea.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://swinsian.com/&#34; target=&#34;_blank&#34;&gt;Swinsian 3&lt;/a&gt; - Paid, doesn&amp;rsquo;t look that much different from Museeks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://audirvana.com/&#34; target=&#34;_blank&#34;&gt;Audirvana&lt;/a&gt; - Paid subscription, audiophile-oriented. Looks high-end, but I&amp;rsquo;m not really into that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What&amp;rsquo;s interesting is that there are a lot of articles on the internet (this post will add one more to the pile) that feature various music players for macOS.
A lot of them suggest video players, like &lt;a href=&#34;https://mac.eltima.com/video-player.html&#34; target=&#34;_blank&#34;&gt;Elmedia&lt;/a&gt;, &lt;a href=&#34;https://iina.io/&#34; target=&#34;_blank&#34;&gt;iina&lt;/a&gt;, and the like.
I found almost no music players with a grid view of your library and a simple experience, like pick an album, hit play, enjoy - most are playlist-oriented.
I guess streaming services won?&lt;/p&gt;
&lt;p&gt;I mean, in Linux, people usually tend to use local-first tools, so it&amp;rsquo;s more expectable to see music players that are either inbuilt, like GNOME Music, or external but in high variety.
On macOS, it seems that the target audience is a bit different, so maybe this explains the far fewer macOS-native music players, as I imagine most of the users used iTunes before and then migrated to Apple Music.
I can be wrong though, but my experience with macOS so far tells me that there are a lot more things people want your money for, as opposed to how things are on Linux.&lt;/p&gt;
&lt;p&gt;I could, of course, try out more cross-platform players, but I covered many of them in my &lt;a href=&#34;https://andreyor.st/posts/2023-11-19-linux-music-players/&#34;&gt;previous post&lt;/a&gt;.
I didn&amp;rsquo;t want to go over all of them again, and my thoughts on them didn&amp;rsquo;t change for the most part, so you can read about them there if you want.
This post turned out to be a lot shorter, but there wasn&amp;rsquo;t that much to talk about, unfortunately.&lt;/p&gt;
&lt;p&gt;If you happen to know anything that is similar to &lt;a href=&#34;https://apps.gnome.org/Music/&#34; target=&#34;_blank&#34;&gt;GNOME Music&lt;/a&gt; UX-wise, but built native for macOS, with FLAC and CUE support - please let me know!
That&amp;rsquo;d be a dream.
For now, I settled on Cog - it was the best of the bunch.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and see you next year!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: MacOS Music Players&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 10 Dec 2025 06:04:00 +0300</pubDate>
    </item><item>
      <title>GNOME is better macOS than macOS</title>
      <link>https://andreyor.st/posts/2025-11-23-gnome-is-better-macos-than-macos/</link>
      <guid>https://andreyor.st/posts/2025-11-23-gnome-is-better-macos-than-macos/</guid>
      <description>&lt;p&gt;Recently, I bought my first-ever MacBook.
I&amp;rsquo;ve spent some time with it, and I gotta say - despite all that hot garbage that is thrown at GNOME for being an OSX clone, GNOME does the job better than I&amp;rsquo;ve expected, and certainly better than Apple.
In some areas, that is.&lt;/p&gt;
&lt;h2 id=&#34;good-old-days-of-linux&#34;&gt;Good old days of Linux&lt;/h2&gt;
&lt;p&gt;A bit of a backstory.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using GNUplusSlashLinux for more than fifteen years.
Most of the time, I used GNOME, starting from GNOME2, moving to Unity maybe for two years, then GNOME Shell, then KDE Plasma 5 for another two years, and switched back to GNOME Shell again.
I&amp;rsquo;m not mentioning some of my at most month-long endeavors to other &lt;abbr title=&#34;Desktop Environment&#34;&gt;DE&lt;/abbr&gt;s, like XFCE, or tiling WMs, because they never stuck with me.
So I&amp;rsquo;ve been there for most releases of GNOME Shell, followed them closely, even used to run Ubuntu GNOME when GNOME Shell became a thing, until it became the default in Ubuntu once again.
Though by that time, I had already moved from Ubuntu to a different distribution for a variety of reasons.&lt;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t always satisfied by GNOME, and was a fair bit vocal about it in the past - even got myself banned from r/gnome subreddit, for shitting on it too much.
That&amp;rsquo;s why I experimented with other desktop environments, particularly Unity and KDE.&lt;/p&gt;
&lt;p&gt;Unity felt like a breath of fresh air after GNOME2, mostly because Canonical took years of people trying to make GNOME2 more OSX-like, and made decent steps in that direction.
A global menu, HUD, blur, buttons on the left - you name it, it was there.
Granted, it wasn&amp;rsquo;t an OSX clone - rather, it was its own thing, and I still remember Unity days fondly.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/unity7.png&#34;
         alt=&#34;Figure 1: Honestly, this was the best desktop&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Honestly, this was the best desktop&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I switched to GNOME Shell almost instantly as it was released as Ubuntu GNOME spin, and while it was a bit janky, Unity started to lose steam, and GNOME looked like a hot new thing.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/gnome3.6.png&#34;
         alt=&#34;Figure 2: Anyone else remember that wallpaper? GNOME sure has come a long way&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Anyone else remember that wallpaper? GNOME sure has come a long way&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I did, however, run Unity on my older PCs, as it was far less taxing on resources than early versions of GNOME3, but then it was discontinued, and long-awaited Unity 8 with Mir never became a thing.
So, when I was fed up with GNOME being a resource hog, often crashing, and moving towards Wayland, which didn&amp;rsquo;t work as good as it was advertised, I decided to try KDE somewhere around 2018.&lt;/p&gt;
&lt;p&gt;And boy, how wrong was I, thinking that KDE is a buggy mess that would drain my resources even worse than GNOME.
KDE Plasma 5 was nothing like I imagined - it was fast, lightweight, and slick.
As a fan of old Unity design and OSX looks, I&amp;rsquo;ve configured my plasma, but it wasn&amp;rsquo;t a full clone, as other people often did.
Instead, I tried to keep Plasma look like Plasma, but feel like a mix between Unity and OSX:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/plasma5.png&#34;
         alt=&#34;Figure 3: To this day, I still think this was beautiful. I&amp;amp;rsquo;ve spent a lot of time fiddling with icon spacings in the top panel, combining widgets, writing my own in QML, just to throw it all away, a few years later&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;To this day, I still think this was beautiful. I&amp;rsquo;ve spent a lot of time fiddling with icon spacings in the top panel, combining widgets, writing my own in QML, just to throw it all away, a few years later&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve run Plasma 5 for about two years, and while I was enjoying it, there still were a lot of jank, bugs, occasional crashes (although Plasma recovered from them beautifully), but GNOME also became a lot better.
So I switched back to GNOME, and I&amp;rsquo;m still running it on my old laptop, where I&amp;rsquo;m writing this part of the text right now:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/gnome42.png&#34;
         alt=&#34;Figure 4: GNOME 42 (Note, I have a 2K display and use GNOME without scaling with enlarged fonts. Helps a lot with too big GNOME UI elements taking up space)&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;GNOME 42 (Note, I have a 2K display and use GNOME without scaling with enlarged fonts. Helps a lot with too big GNOME UI elements taking up space)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, there are no fancy extensions - everything is the same as in a stock Fedora Workstation, because it is a stock Fedora Workstation.
And I love it.&lt;/p&gt;
&lt;p&gt;Over the years, I had a love-hate relationship with GNOME, but after a while, I came to accept it as it is, and now it feels like a perfect desktop environment for me personally.
That, of course, is thanks to GNOME developers actually trying to make GNOME better, and me buying into their vision of what an OS should look and feel like.
There is still some jankiness to it, but I&amp;rsquo;m willing to overlook it at this point, because after years of searching, I couldn&amp;rsquo;t find anything that suits my workflow better.
And I&amp;rsquo;m fine with that.&lt;/p&gt;
&lt;h2 id=&#34;a-disclaimer&#34;&gt;A disclaimer&lt;/h2&gt;
&lt;p&gt;Before I go crazy on bashing macOS, I need to make a disclosure - &lt;strong&gt;I AM BIASED&lt;/strong&gt;.
I&amp;rsquo;ve been using GNOME for a lot of time, and a lot of things that feel logical to me may not feel logical at all to others.
Especially for macOS users.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m fully aware of that.&lt;/p&gt;
&lt;p&gt;Now, with that outta the way, let&amp;rsquo;s begin.&lt;/p&gt;
&lt;h2 id=&#34;a-new-laptop&#34;&gt;A new laptop&lt;/h2&gt;
&lt;p&gt;As I mentioned, I&amp;rsquo;ve just got myself a MacBook.
I did it because today&amp;rsquo;s laptop market is a bit odd.
It&amp;rsquo;s hard to find a decent non-gaming laptop with good specs.
I mean, there are Lenovo ThinkPads, ThinkBooks, and even IdeaPads that are decent, but I already owned an IdeaPad, and while it served me for six years and I liked it, I don&amp;rsquo;t know if I want another one.
Other brands may offer similar hardware, but I didn&amp;rsquo;t investigate much.&lt;/p&gt;
&lt;p&gt;One of the reasons is OS choices.
You see, I have run Linux as my main OS since around 2008.
But I still have to use Windows from time to time.
During university years, most of the non-programming software was Windows-only.
After university, I had to use Windows to do media stuff, like music recording and video production, or design.&lt;/p&gt;
&lt;p&gt;Design is probably the only task Linux can handle without much of a hassle, given that there are decent programs for that.
For instance, I don&amp;rsquo;t mind GIMP, Krita, or Inkscape for most of my image-related tasks.
I can even do video editing in Blender (and I do), but for some reason, it just works better under Windows.
Audio production - not a chance.
You&amp;rsquo;ll find me dead in the ground before I figure out how to set up a realtime kernel and configure Jack.
Not to mention, VSTs just don&amp;rsquo;t work because many are relying on Windows APIs, and patching them through Wine is not a path I would like to walk.&lt;/p&gt;
&lt;p&gt;So I had to use Windows, constantly rebooting from Linux to it every time I wanted to record myself, or work on some video for my channel.
And I also had to use the one that came with my laptop - 6 years ago, it was Windows 10.&lt;/p&gt;
&lt;p&gt;My parents recently got a new laptop with Windows 11 on it, and my god, it is horrible.
After using Linux for more than fifteen years, I can&amp;rsquo;t even imagine how Microsoft is still able to get away with it.
Ads are everywhere - on the lockscreen, in the start menu, in notifications, etc.
You can&amp;rsquo;t even activate it without connecting to the network and signing into a Microsoft account.&lt;/p&gt;
&lt;p&gt;Oh, and updates.
Fucking updates are being forced, while I&amp;rsquo;m waiting for the next 5 hours until my video finishes rendering, because my laptop is too old to render in 4K.&lt;/p&gt;
&lt;p&gt;Yes, it&amp;rsquo;s possible to &amp;ldquo;debloat&amp;rdquo; Windows, remove most of the jank they added, disable automatic updates, and have a decent, clean experience.
I just don&amp;rsquo;t want to do that.
The whole point of an operating system, to me, is to stay out of the way while managing resources, processes, and making sure my shit is done without major hiccups.&lt;/p&gt;
&lt;p&gt;Now, when Windows 10 support is ending, all we&amp;rsquo;re left with is Windows 11, and god knows what bullshit awaits us in Windows 12.&lt;/p&gt;
&lt;p&gt;So I thought to myself: &amp;ldquo;Ok, I like Linux, but I want to be able to do my media-related stuff, and I don&amp;rsquo;t want to invest in making Linux be able to do so. What options do I have other than that?&amp;rdquo;
I just applied to a new job, and almost everyone there uses a Mac, and many of them are musicians, either hobbyists like myself or even professionals.
After asking around, it appeared to me that switching to macOS could be the solution I&amp;rsquo;m looking for.
It&amp;rsquo;s a Unix, so I guess my Linux habits won&amp;rsquo;t have to go through WSL hoops, and it has world-class support for media tasks.
I think macOS can even be considered media-first when it comes to production, unlike Linux or Windows.&lt;/p&gt;
&lt;p&gt;So I saved some money and got myself a new MacBook Pro, with M4, and decent specs.
While the laptop itself is nice - I like the aluminium body, keyboard is nice (although I had an opportunity of using their butterfly one, and liked it better), the screen is gorgeous, and even the laptop speakers are great, but&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;hellip;but the OS&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;macos&#34;&gt;macOS&lt;/h2&gt;
&lt;p&gt;This is the most counter-intuitive, user-unfriendly, confusing piece of software that I&amp;rsquo;ve used in my life.
And I worked as a consultant in a cellphone store and used software for cashiers, yet it still was not as horrid.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sure nothing I will write here will be new, and I&amp;rsquo;m committing an &amp;ldquo;internet crime&amp;rdquo; of &amp;ldquo;beating a dead horse&amp;rdquo; here, while it&amp;rsquo;s probably already reduced to vapors, but I still want to get it out of my system.&lt;/p&gt;
&lt;h3 id=&#34;the-desktop&#34;&gt;The Desktop&lt;/h3&gt;
&lt;p&gt;My laptop came with macOS 15 Sequoia preinstalled, so I haven&amp;rsquo;t used previous versions much, although I had used a Mac a bunch of times in the past when I was at the university ten plus years ago.
However, I decided to immediately upgrade to the 26.1 Tahoe, so I wouldn&amp;rsquo;t get too used to the good-looking interface, and instead learn to get comfortable with this liquid glass crap.
So I didn&amp;rsquo;t touch macOS for some years, and some things have changed, but the majority of annoyances I remember are still here.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on different desktops/WMs for macOS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve started receiving some comments on this post, and I&amp;rsquo;d like to clarify that I&amp;rsquo;m aware of other window manager alternatives for macOS, like &lt;a href=&#34;https://github.com/nikitabobko/AeroSpace&#34; target=&#34;_blank&#34;&gt;AeroSpace&lt;/a&gt;, &lt;a href=&#34;https://github.com/koekeishiya/yabai&#34; target=&#34;_blank&#34;&gt;Yabai&lt;/a&gt; and the like.&lt;/p&gt;
&lt;p&gt;First, I&amp;rsquo;m not a fan of tiling window managers.
Personally, I almost always have one window per desktop.
Tiling never stuck with me. I&amp;rsquo;ve tried it several times during these fifteen plus years, and I don&amp;rsquo;t really feel the need for a keyboard-driven environment besides my Emacs.
I mostly use touchpad gestures and the overview/mission control feature when I need to switch windows.&lt;/p&gt;
&lt;p&gt;Secondly, I don&amp;rsquo;t really have &lt;em&gt;that many&lt;/em&gt; issues with the current macOS WM, and I don&amp;rsquo;t really want to replace it.
I was a GNOME user, remember?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;virtual-desktops&#34;&gt;Virtual desktops&lt;/h4&gt;
&lt;p&gt;As an ex-GNOME user, I like my virtual desktops.
MacOS has had virtual desktops for a long time, but I think GNOME handled those better.&lt;/p&gt;
&lt;p&gt;First of all, switching with the touchpad gesture feels a lot slower.
In GNOME, it wasn&amp;rsquo;t an animation - the speed was tied directly to how fast you move your fingers, with easing after you release them.
I got used to switching between desktops with a lot of speed, and on macOS, it&amp;rsquo;s not like that.&lt;/p&gt;
&lt;p&gt;It seems it is also tied to the speed of the gesture, but it feels like there&amp;rsquo;s a cap on the maximum possible speed:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/desktop-switching.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;An additional feature of GNOME is that it will automatically create additional virtual desktops once you&amp;rsquo;ve filled all of them, and there&amp;rsquo;s no limit to how many you can have.
I usually have 4-5 desktops, but when I&amp;rsquo;m not working on something, it&amp;rsquo;s nice that I can only have one or two.&lt;/p&gt;
&lt;p&gt;In macOS, you can have as many desktops as you want, however, they&amp;rsquo;re not added automatically.
Or at least I couldn&amp;rsquo;t find a setting for that.
Because of that, even if I&amp;rsquo;m not using all of them, sometimes a stray window is sitting on the last desktop, and I have to go through all of them to get to it.&lt;/p&gt;
&lt;h4 id=&#34;fullscreen-and-maximize-button&#34;&gt;Fullscreen and maximize button&lt;/h4&gt;
&lt;p&gt;For some reason, the developers decided that the maximize button should instead act like a fullscreen button in macOS.
When you maximize a window, it is moved to its own, dedicated virtual desktop - and &lt;strong&gt;I like it&lt;/strong&gt;.
I have used this pattern in GNOME for a long time by installing an &lt;a href=&#34;https://extensions.gnome.org/extension/8226/maximize-to-empty-workspace-2025/&#34; target=&#34;_blank&#34;&gt;extension&lt;/a&gt; that brings this feature into GNOME.&lt;/p&gt;
&lt;p&gt;However, and it is a big &lt;strong&gt;however&lt;/strong&gt;, in GNOME, when I maximize a window, it creates a virtual desktop next to the one I&amp;rsquo;m on.
In macOS, it also creates a virtual desktop, but it moves it to the far right.&lt;/p&gt;
&lt;p&gt;So, imagine I&amp;rsquo;m browsing the web, seeing something interesting, and I want to open Emacs to take a note.
I open Emacs, maximize it, and on the desktop to the left of Emacs, I still have my browser, and I can switch between these back and forth.
In macOS, if I do this, the window is moved to a desktop at the far end of the list of desktops.
You can rearrange those manually, but it&amp;rsquo;s clumsy.
I would much prefer if the desktop were created to the right of the current one.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/emacs-on-far-right.png&#34;
         alt=&#34;Figure 5: Emacs was opend on Desktop 1, but after maximizing it is now essentially at Desktop 5&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;Emacs was opend on Desktop 1, but after maximizing it is now essentially at Desktop 5&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You can prevent this, in some form, by turning on the &amp;ldquo;Automatically rearrange Spaces based on most recent use&amp;rdquo; in the settings.
Then, a new fullscreen desktop is created to the right of the one you&amp;rsquo;re currently on, which is nice, however, then the spaces get rearranged all the time.
Like, when you&amp;rsquo;re opening a link from the messenger, you switch to a desktop that has the browser open.
The spaces get rearranged, such that the desktop with the messenger is next to the one with the browser, so you have to find the other one that previously was inbetween.
It&amp;rsquo;s so bizarre that we can&amp;rsquo;t have fullscreen spaces created next to the current one without automatic rearrangement.&lt;/p&gt;
&lt;p&gt;And, because it is a fullscreen mode, it also makes things go a bit haywire for some applications.
Emacs doesn&amp;rsquo;t like this mode in particular.&lt;/p&gt;
&lt;p&gt;Right now, I&amp;rsquo;m using four virtual desktops and manually organizing those, but maybe I need to adjust my usage pattern.
Speaking of virtual desktops, let&amp;rsquo;s look at the Mission Control thing.&lt;/p&gt;
&lt;h4 id=&#34;mission-control&#34;&gt;Mission Control&lt;/h4&gt;
&lt;p&gt;That&amp;rsquo;s another pain point for me.
You see, GNOME also has something akin to Mission Control - you swipe up with three fingers, and you see all your open windows:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/overview-gnome.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can then move your windows between desktops or switch between them.&lt;/p&gt;
&lt;p&gt;MacOS also has this, with the exact same gesture:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/mission-control.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;However, it is far less useful.&lt;/p&gt;
&lt;p&gt;In GNOME, I can close windows in the Overview:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/overview-action1.png&#34;
         alt=&#34;Figure 6: This close button is part of the Overview, not the window manager&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;This close button is part of the Overview, not the window manager&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I can tweak the dock:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/overview-action2.png&#34;
         alt=&#34;Figure 7: Actually, the dock is only visible in Overview&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 7: &lt;/span&gt;Actually, the dock is only visible in Overview&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I can start typing, and the search appears:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/overview-action3.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I can even swipe up again and bring up the applications menu:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/overview-action4.png&#34;
         alt=&#34;Figure 8: Not that I use it that much though&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 8: &lt;/span&gt;Not that I use it that much though&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;There&amp;rsquo;s a lot of control!
Wanna know how much you can control in the Mission Control?&lt;/p&gt;
&lt;p&gt;You can move windows and desktops around.&lt;/p&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;What mission?
What control?
You can&amp;rsquo;t do anything.&lt;/p&gt;
&lt;p&gt;Sure, one advantage macOS&amp;rsquo; mission control has is that you can move entire desktops around - in GNOME, you can&amp;rsquo;t rearrange desktops themselves, only windows.
And it plays nicely, with all this full-screen nonsense, but I still much prefer the GNOME approach here.&lt;/p&gt;
&lt;h3 id=&#34;the-dock&#34;&gt;The Dock&lt;/h3&gt;
&lt;p&gt;Dock is a weird concept.
It&amp;rsquo;s cool to have it, and I remember in my early Linux days I wanted a macOS-like dock so badly that I tried to make it out of existing panels and custom widgets.
I installed various dock plugins in my desktop environments just to have it zoom in on icons when I hover over them.
These days are long past.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/cairo-dock.png&#34;
         alt=&#34;Figure 9: remember Cairo dock?&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 9: &lt;/span&gt;remember Cairo dock?&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/plank.jpg&#34;
         alt=&#34;Figure 10: remember Plank?&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 10: &lt;/span&gt;remember Plank?&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;GNOME made a smart decision to only show the dock when you&amp;rsquo;re in Overview - their &amp;ldquo;Mission Control&amp;rdquo; variant.
You don&amp;rsquo;t need the dock constantly taking vertical space from your windows, and you don&amp;rsquo;t have to deal with it showing up accidentally when you simply hover the mouse pointer at the bottom of the screen.
Or at the side of the screen if it is your thing.&lt;/p&gt;
&lt;p&gt;When it is only inside the Overview/Mission control, it makes sense as a favorites bar and a way of switching between applications.
I haven&amp;rsquo;t used &lt;kbd&gt;Alt&lt;/kbd&gt;+&lt;kbd&gt;Tab&lt;/kbd&gt; (or &lt;kbd&gt;⌘ command&lt;/kbd&gt;+&lt;kbd&gt;⭾ Tab&lt;/kbd&gt;) in years because of that.
I would much prefer for the dock to be only visible in Mission Control, but sadly, there&amp;rsquo;s no way of doing it in macOS, as far as I can see.
Moreover, Dock becomes useless in Mission Control specifically, so it won&amp;rsquo;t work that well in macOS.&lt;/p&gt;
&lt;p&gt;What baffles me is that when you close an app, it stays in the dock, taking up space.
Again, there seems to be no way of disabling it.
Disabling the &amp;ldquo;Show suggested and recent apps in Dock&amp;rdquo; in system settings doesn&amp;rsquo;t affect this behavior.&lt;/p&gt;
&lt;p&gt;You have to either use &lt;kbd&gt;⌘ Q&lt;/kbd&gt;, or right-click on the dock item and choose &amp;ldquo;close&amp;rdquo;.
What&amp;rsquo;s the red button in the window for then?
Usually, the app simply continues working in the background, as if minimized.&lt;/p&gt;
&lt;p&gt;Speaking of which, so far only the minimize button seems to work in a sane manner.&lt;/p&gt;
&lt;p&gt;Sure, there&amp;rsquo;s little point in actually closing applications, given that this laptop has a lot of RAM and CPU power, but it always felt weird to me that apps want to stay open all the time.
I&amp;rsquo;m done with you - why do you think that you&amp;rsquo;re so important that you shouldn&amp;rsquo;t be closed?
Do what you&amp;rsquo;ve been told.&lt;/p&gt;
&lt;h3 id=&#34;the-finder&#34;&gt;The Finder&lt;/h3&gt;
&lt;p&gt;Linux has always had weird file managers.
To me, nothing beats Microsoft&amp;rsquo;s Windows 7 file explorer - it was the least BS one in my opinion.
GNOME&amp;rsquo;s Nautilus, or Files, as it is called nowadays, had a few long-standing problems, some of which date back ten plus years.
KDE&amp;rsquo;s Dolphin was nice, but too had some weird quirks.
However, it&amp;rsquo;s nothing in comparison to macOS Finder.&lt;/p&gt;
&lt;p&gt;See the screenshot?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/finder.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;A normal file view, right?
Now, what should happen if I shrink the window?&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/finder-resize.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The what?
Who thought that this was a good idea?
For those who didn&amp;rsquo;t get it, the grid of items remains the same despite the size of the window!
Like, seriously?&lt;/p&gt;
&lt;p&gt;The oddities don&amp;rsquo;t end there.
Where&amp;rsquo;s the current path?
For some reason, you can only see it when holding the &lt;kbd&gt;⌥ option&lt;/kbd&gt;, it appears at the bottom of the window.
You can, in fact, toggle it in the settings so it is always shown, and while you can click on it to navigate, you can&amp;rsquo;t edit it, as it seems.&lt;/p&gt;
&lt;p&gt;What really baffles me though is that it seems impossible to shift-select multiple files in grid view - only in list view.
Even though, if you do shift-select files in list view, and switch back to the grid view, files stay selected.
Seems to be related to how the &lt;a href=&#34;#the-media-viewer&#34;&gt;media viewer works&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another oddity is that when moving directories around, there&amp;rsquo;s no option to merge directories with the same name by default.
I mean, when I move a directory to a different place, where another directory exists with the same name, I expect them to be merged, but the pop-up only says this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/no-merge.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;When the &lt;kbd&gt;⌥ option&lt;/kbd&gt; key is pressed preemptively and held during the drag, the option to merge directories appears:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/merge.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Like, you need to know, before the hand, that the target location you&amp;rsquo;ve chosen contains a folder with the same name you&amp;rsquo;re moving right now.
And if you didn&amp;rsquo;t, you need to repeat the drag.
Why not show it by default?&lt;/p&gt;
&lt;p&gt;For the record, when the same thing is done in the GNOME file manager, it asks you if you want to merge directories, but you can&amp;rsquo;t replace them, so you can&amp;rsquo;t ever lose data.
And if it contains files with the same names, it asks for each file if you want to replace it, or keep both.
Of course, you can choose to replace all files, so it wouldn&amp;rsquo;t drag:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/gnome-merge.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Cutting files is also super weird.
You first copy the file as normal, then proceed to the directory you want to move the file, and press &lt;kbd&gt;⌘ command&lt;/kbd&gt;+&lt;kbd&gt;⌥ option&lt;/kbd&gt;+&lt;kbd&gt;v&lt;/kbd&gt;.
Not only does the shortcut itself make your hand curl up as if you were a lobster, but also the semantics of this operation feel extremely weird - you copied the file, after all, why would it move afterwards?
I guess, it&amp;rsquo; handy in cases when you thought you wanted to copy the file, but you actually decided to move it, so you don&amp;rsquo;t need to input a whole new shortcut again, but it&amp;rsquo;s a minor win in my book.&lt;/p&gt;
&lt;p&gt;Thankfully, I use graphical file managers rarely, so I can continue living in my comfort zone of Emacs&amp;rsquo; DIRED.&lt;/p&gt;
&lt;h4 id=&#34;files-and-folders&#34;&gt;Files and folders&lt;/h4&gt;
&lt;p&gt;But, while we&amp;rsquo;re at it, let&amp;rsquo;s talk about files in general.&lt;/p&gt;
&lt;p&gt;I have some local music stored in the &lt;code&gt;Music&lt;/code&gt; folder.
Some videos and films are stored in the &lt;code&gt;Videos&lt;/code&gt; folder.
I also have pictures stored in the &lt;code&gt;Pictures&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Crazy, right?
Imagine using the file system to store files systematically?&lt;/p&gt;
&lt;p&gt;I also try to keep things organized, so I manage all these with some directories, like &lt;code&gt;band-name/album-name/track-name&lt;/code&gt; in case of music files, or &lt;code&gt;year/place-name/photo&lt;/code&gt; in case of photos.
I like it because if I want to listen to something, I can just drop the folder into the player, or open the image folder and relive those moments.
Organizing these with folders is also handy for backing these things up - just drop the folder to the external drive and you&amp;rsquo;re good to go.&lt;/p&gt;
&lt;p&gt;In macOS, as it seems, tags are the way the system wants to work with files.
It&amp;rsquo;s a different approach, and I&amp;rsquo;m not entirely opposed to that, since filesystems are an illusion, after all.&lt;/p&gt;
&lt;p&gt;But every once in a while, I open the &lt;code&gt;Music&lt;/code&gt; folder, and I see a second &lt;code&gt;Music&lt;/code&gt; folder inside it.
Apparently, it is created when opening the Music app.
I can&amp;rsquo;t use the Music app because it can&amp;rsquo;t play FLAC, which is what the majority of my local library is encoded in.&lt;/p&gt;
&lt;p&gt;When I open the &lt;code&gt;Videos&lt;/code&gt; folder, I often find a &lt;code&gt;TV&lt;/code&gt; folder inside.
I&amp;rsquo;m not sure what app creates it, but it wasn&amp;rsquo;t done by me, as I never launched the TV app.
And it appears there far more regularly than the &lt;code&gt;Music/Music&lt;/code&gt; one.&lt;/p&gt;
&lt;p&gt;Other apps often create their own folders anywhere they want.
The OrbStack app creates an &lt;code&gt;OrbStack&lt;/code&gt; folder in &lt;code&gt;$HOME&lt;/code&gt;.
Some other app I installed created a folder in the &lt;code&gt;Music&lt;/code&gt; folder for some reason, even though it didn&amp;rsquo;t store &lt;em&gt;music&lt;/em&gt; in it, just some audio files.&lt;/p&gt;
&lt;p&gt;It feels like that this is not my computer, but one I share with everyone else, and watch they do as they please with my filesystem.
Never once was this a problem in Linux.&lt;/p&gt;
&lt;p&gt;Why can&amp;rsquo;t apps keep their files to themselves?
I&amp;rsquo;m tempted to create things like &lt;code&gt;Music/My Music&lt;/code&gt;, or &lt;code&gt;Pictures/My Pictures&lt;/code&gt;, and use them specifically, forgetting about the default &lt;code&gt;Music&lt;/code&gt;, &lt;code&gt;Pictures&lt;/code&gt;, &lt;code&gt;Videos&lt;/code&gt; thing, but it is such a cumbersome solution.
It feels like, when you invite friends to a party, and they go to your bookshelf, and decide that they&amp;rsquo;ll put some of their own stuff on it for the time being.
And when they leave, they forget to take their stuff, but you don&amp;rsquo;t want to touch it, as it is not exactly yours.
And you can&amp;rsquo;t throw it out, as your friends will be mad.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know.&lt;/p&gt;
&lt;h3 id=&#34;the-media-viewer&#34;&gt;The media viewer&lt;/h3&gt;
&lt;p&gt;Oh, the image viewer.&lt;/p&gt;
&lt;p&gt;Let me ask you a question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You have a directory with some photos.
You want to go through these photos in the order taken and view them.
What do you do?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In Linux, or Windows for that matter, the answer is simple: you double-click on the image you want to start with, the image viewer is opened, and you can use the arrow keys to go back and forth.
Simple and effective!&lt;/p&gt;
&lt;p&gt;What happens when you do it in macOS Finder?
Well, the image viewer still opens, but the arrow keys do nothing!
No, in order to go through images, you need to select the items you want to view, hover over the File menu in the top bar, press the &lt;kbd&gt;⌥ option&lt;/kbd&gt; key, and select &amp;ldquo;Start slideshow &lt;code&gt;N&lt;/code&gt; items&amp;rdquo;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/slideshow.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;HUH?
Slideshow is cumbersome, as it is a slideshow - it&amp;rsquo;s not meant for going through images manually.&lt;/p&gt;
&lt;p&gt;Alternatively, you can use a different viewer, called &amp;ldquo;Quick Look&amp;rdquo;, which supports arrow keys.
Horray!
But what is it?
If you&amp;rsquo;re in grid view, why are the arrow keys following the grid too?&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/quick-view.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HUUUUUH&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;Who thought that this was a good idea?
Hopefully, I won&amp;rsquo;t repeat this question all too many times.&lt;/p&gt;
&lt;p&gt;The only reasonable way of using it is by switching to the list view and using the up and down arrow keys.
Which is still not great, because Quick View is meant to be viewed temporarily.
Any accidental click outside of it will close it, and you&amp;rsquo;ll have to find where you were and start from there.&lt;/p&gt;
&lt;p&gt;You can put it into fullscreen mode, but then the arrow keys stop working.
This seems like such a basic feature for an image viewer, but somehow they&amp;rsquo;ve managed to make it unusable.
Not only that, but if this folder has any non-image files, like text files or PDFs, they&amp;rsquo;ll be included in the quick view too.&lt;/p&gt;
&lt;p&gt;I understand that the purpose of Quick View is to view files quickly, and often it is a great thing to have, but at the same time, it&amp;rsquo;s super weird in behavior.&lt;/p&gt;
&lt;h3 id=&#34;hardware-accessibility&#34;&gt;Hardware accessibility&lt;/h3&gt;
&lt;p&gt;OK, I can go on and on about the software part of the os, but to be honest, all of this is covered by other people rather well.
And, in truth, I couldn&amp;rsquo;t be bothered to try all other preinstalled software, because it&amp;rsquo;ll take a lot of time to put it into this already long article, but also because I don&amp;rsquo;t want to.
For instance, the Music app is also weird, and I already have an &lt;a href=&#34;https://andreyor.st/posts/2023-11-19-linux-music-players/&#34;&gt;extensive post about how Linux music players are weird&lt;/a&gt;, so it goes without saying that I&amp;rsquo;ll need to replace it with something else.
Like, the Quick View can play FLAC without any issues, but the Music app (formerly iTunes, I believe) can&amp;rsquo;t.
Even GNOME&amp;rsquo;s player could do that, and it kinda copies Apple&amp;rsquo;s Music app in some aspects.
Reencoding all my library into ALAC - Apple&amp;rsquo;s equivalent of FLAC for lossless audio is not an option for me.
I did it once before when I was a &lt;em&gt;happy owner&lt;/em&gt; of an old 4th-gen iPod touch, but never again - it is pointless, there are better music players out there.&lt;/p&gt;
&lt;p&gt;So to me, the silver lining is that GNOME&amp;rsquo;s inbuilt software is in a lot of ways better than one in macOS.
And KDE has even better software than GNOME in a lot of cases.
So instead, let&amp;rsquo;s talk about hardware oddities and their operating system counterparts.&lt;/p&gt;
&lt;h4 id=&#34;the-microphone&#34;&gt;The Microphone&lt;/h4&gt;
&lt;p&gt;So, while I do care about my privacy, I can&amp;rsquo;t call myself a privacy maniac.
However, one thing I like to have in my devices is the ability to mute the microphone.
It&amp;rsquo;s best when there&amp;rsquo;s a hardware switch for that, but it&amp;rsquo;s so rare that I&amp;rsquo;ve only seen it once in my life on some Lenovo laptop.&lt;/p&gt;
&lt;p&gt;I mean, it&amp;rsquo;s simply more convenient to do that than switch to a specific application that currently uses the microphone and toggle it there.&lt;/p&gt;
&lt;p&gt;So, on Linux, I used the microphone key found on my laptop&amp;rsquo;s keyboard.
It muted the microphone in the system settings.&lt;/p&gt;
&lt;p&gt;When I got my Mac, I examined the keyboard, and found almost all usual shortcuts - you can change screen brightness on &lt;kbd&gt;F1&lt;/kbd&gt; and &lt;kbd&gt;F2&lt;/kbd&gt;, you can change volume on &lt;kbd&gt;F11&lt;/kbd&gt; and &lt;kbd&gt;F12&lt;/kbd&gt;, and there&amp;rsquo;s the microphone icon on &lt;kbd&gt;F5&lt;/kbd&gt;.
So I naturally assumed that this was a button to mute the microphone, after all, my old laptop had it too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I assumed wrong.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s &lt;strong&gt;no way&lt;/strong&gt; to disable the microphone in macOS via inbuilt means.
The only thing you can do is to manually set the volume input gain level to 0, effectively making the microphone deaf.&lt;/p&gt;
&lt;p&gt;Wanna know what the microphone button does then?
I&amp;rsquo;ll show you:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/dictation.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Yup, it asks you if you want to use the speech-to-text feature.
&lt;em&gt;Cool&lt;/em&gt;, right?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And you can&amp;rsquo;t change what this button does.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can set a different shortcut for dictation in the settings, but look what happens when you press the microphone key:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/dictationship.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It changes itself back to this button if you click &amp;ldquo;don&amp;rsquo;t ask again&amp;rdquo;!
And then it asks you again once you press it!
So what was the point of providing &amp;ldquo;don&amp;rsquo;t ask again&amp;rdquo; then?&lt;/p&gt;
&lt;p&gt;Though I&amp;rsquo;ve managed to defeat this beast of a problem by writing some AppleScript.
This script can be executed in the Shortcuts app, and by analyzing its output, we can rename the shortcut accordingly:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/shortcuts.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;After adding this shortcut to the &amp;ldquo;Controls&amp;rdquo; menu, it acts as a mute button:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/shortcut.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Works well so far, and even remembers the current input level value, so I can still adjust it if needed.
Even more, it works better than it did on Linux, because it constantly forgot what level the mic was set to and chose a default value of 20%, which was too low.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a text version of the script, if anyone needs it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-applescript&#34; data-lang=&#34;applescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;run&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parameters&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;font-weight:bold&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;currentVolume&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; volume &lt;span style=&#34;font-weight:bold&#34;&gt;of&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get volume settings&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;currentVolume&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;is&lt;/span&gt; 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;font-weight:bold&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;storedVolume&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;do shell script&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;defaults read com.andreyorst.mictoggle volume&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;font-weight:bold&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;storedVolume&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;to&lt;/span&gt; 50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;do shell script&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;defaults write com.andreyorst.mictoggle volume -int &amp;#34;&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;storedVolume&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set volume&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; volume &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;storedVolume&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Unmute&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;do shell script&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;defaults write com.andreyorst.mictoggle volume -int &amp;#34;&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;currentVolume&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set volume&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; volume 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mute&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Error&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;run&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can&amp;rsquo;t share the whole script because no way I&amp;rsquo;m making an iCloud account for that.&lt;/p&gt;
&lt;h4 id=&#34;the-keyboard-layout&#34;&gt;The keyboard layout&lt;/h4&gt;
&lt;p&gt;Not strictly about the hardware part, since the keyboard itself is pretty good.
It&amp;rsquo;s a bit of a shame that Apple stopped using their Butterfly switches, as I did like them more than the current scissor ones, but the keyboard is still better than the one on my old laptop.&lt;/p&gt;
&lt;p&gt;One thing that bothers me, and which I got very accustomed to, is the fact that GNOME can remember keyboard layout per window:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/remember-layout.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;MacOS can&amp;rsquo;t do that - and I don&amp;rsquo;t know what is the reason for that.
The settings page for layouts has a setting called &amp;ldquo;Automatically switch to a document&amp;rsquo;s input source&amp;rdquo;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/layout-settings.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;However, I&amp;rsquo;m not sure what it does.
It seems to work sometimes, but other times it does the opposite of what I want to.
I only have two layouts.
Is it that hard to keep track of that amount of data per window?&lt;/p&gt;
&lt;h4 id=&#34;the-keyboard-layout--physical&#34;&gt;The keyboard layout (physical)&lt;/h4&gt;
&lt;p&gt;Though let&amp;rsquo;s touch the keyboard one more time.
I know that Apple has at least two keyboard layouts for different markets - one for the US and one for Europe.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/us-layout.png&#34;
         alt=&#34;Figure 11: US layout&#34; width=&#34;100%&#34; height=&#34;auto&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 11: &lt;/span&gt;US layout&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-11-23-gnome-is-better-macos-than-macos/europe-layout.png&#34;
         alt=&#34;Figure 12: European layout&#34; width=&#34;100%&#34; height=&#34;auto&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 12: &lt;/span&gt;European layout&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I specifically wanted the US layout, because all other laptops and standalone keyboards I had in my entire life had this kind of layout.
Never once in my life have I seen the European layout on any device.&lt;/p&gt;
&lt;p&gt;But, for some unknown reason, Apple sells its laptops with a European layout in my area, and when my wife had a Mac, it had that.
Every time I used it, I was fighting my muscle memory.&lt;/p&gt;
&lt;p&gt;Sure, it has more keys, and these contain some characters otherwise inaccessible without switching the layout, so it can look like Apple does a good thing.
However, literally no one except Apple users had seen this layout, and it makes no sense to them.
In my particular case, some already existing keys in the European layout are placed differently, like &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, since I didn&amp;rsquo;t want to deal with that, I got myself a version with a US layout.
Thankfully, there&amp;rsquo;s a &amp;ldquo;PC&amp;rdquo; layout in the system settings, so I don&amp;rsquo;t have to relearn anything.
Using the &amp;ldquo;PC&amp;rdquo; layout on a European keyboard, however, is even more cumbersome.&lt;/p&gt;
&lt;h4 id=&#34;no-middle-click-on-the-touchpad&#34;&gt;No middle click on the touchpad&lt;/h4&gt;
&lt;p&gt;For some reason, there&amp;rsquo;s no such thing as a middle-click on a touchpad.
In Linux, it is usually mapped to clicking with three fingers at the same time.
I&amp;rsquo;ve been using it in Firefox a lot, and to paste stuff into the terminal once in a while.&lt;/p&gt;
&lt;p&gt;However, in macOS, my muscle memory is now against me.
I click with three fingers in Firefox, and usually it brings up the right-click menu, which is fine at least.
But sometimes it is registered as a left-click instead, and it is super annoying.
Re-learning to use @@html:&amp;lt;kbd&amp;gt;⌘ command&amp;lt;/kbd&amp;gt; click will take some time, I guess&lt;/p&gt;
&lt;h4 id=&#34;the-camera-cutout&#34;&gt;The camera cutout&lt;/h4&gt;
&lt;p&gt;Same as with the microphone, I&amp;rsquo;d like to have a physical way of blocking the camera, but because Apple moved towards a custom-shaped display matrix, it can&amp;rsquo;t be done as easily as before.
It has a lot of sensors there, and blocking them with a huge plastic cover will make it impossible to close the laptop lid.&lt;/p&gt;
&lt;p&gt;Again, not strictly about the hardware side of things, but the display in general feels weird because of this notch - it&amp;rsquo;s right in the middle of the screen, and I&amp;rsquo;m used to having the clock there, after years of using GNOME.
Some say it&amp;rsquo;s more logical to have them at the far right side, as it is commonly done on phones, but phones have a much smaller and narrower screen.
The same goes for notifications - having them in the middle feels more natural to me, because most of the content I&amp;rsquo;m working with is somewhere in the middle.
But your opinion may vary (as if anything else I said here can be universally agreed on).&lt;/p&gt;
&lt;h3 id=&#34;the-good-parts&#34;&gt;The good parts&lt;/h3&gt;
&lt;p&gt;OK, enough bitching around, let&amp;rsquo;s discuss some good parts.&lt;/p&gt;
&lt;p&gt;The screen itself is gorgeous, colors are vivid yet natural, and the 14-inch model is actually both a bit bigger and a bit taller than my old 13-inch laptop.
I like the screen a lot.
I didn&amp;rsquo;t go for the nano-texture display, as I don&amp;rsquo;t work in environments where reflections are problematic, so I can&amp;rsquo;t say how it affects image quality.
Maybe if I did, it&amp;rsquo;d be in the bad section.&lt;/p&gt;
&lt;p&gt;The speakers are pretty good.
And for a laptop, they&amp;rsquo;re actually amazing.
They have depth, the upmp, and are loud enough to watch films with comfort - can&amp;rsquo;t say this about any other laptop I&amp;rsquo;ve had before.&lt;/p&gt;
&lt;p&gt;Touchpad - oh, the touchpad.
Simply put, the fact that it is a lot bigger (in fact, they had even bigger ones before), and I can press on it absolutely everywhere, is amazing.
I was also surprised to learn that they aren&amp;rsquo;t actually pressed in physically.
Instead, it is a glass surface, which has haptic feedback that simulates the click.
Purely amazing.
I&amp;rsquo;ve spent a long time trying to find anything remotely close to these touchpads on other laptops, but I never could find one.&lt;/p&gt;
&lt;p&gt;M4 Pro CPU is a beast.
Recently, I forgot a passphrase to one of my GPG keys and tried to brute-force it.
My old laptop had AMD Ryzen™ 7 3750H, which isn&amp;rsquo;t fast by today&amp;rsquo;s standards, but it wasn&amp;rsquo;t a slow CPU either - it handled all of my tasks without major hiccups.
I tried it first on the old laptop, and it could try about ~45 passphrases per second.
The M4 could try ~750 passphrases per second.
Everything is &lt;strong&gt;so fast&lt;/strong&gt; I can&amp;rsquo;t believe it.&lt;/p&gt;
&lt;p&gt;The macOS itself isn&amp;rsquo;t all that bad.
As a matter of fact, writing this post helped me find how to fix a lot of problems I initially had - this post was a lot longer before that, but I had to cut stuff from it, as it was no longer applicable.
There are still some oddities - it constantly bothers me with asking permission to run apps for the first time, because I install them through &lt;code&gt;brew&lt;/code&gt;, or downloaded from the official website (again, I&amp;rsquo;m not making an Apple account, no, no).
But I finally have a machine on which I can do both my programming tasks and media tasks without needing to keep two different operating systems to handle each task specifically.
Finally, I can record my music with my right hand while writing code with the left - a dream.&lt;/p&gt;
&lt;p&gt;Even the liquid glass thing is not as bad as I thought it would be.
Thankfully, Apple added a tinted style to it, so it is less transparent, which helps readability.&lt;/p&gt;
&lt;p&gt;And overall, I really like the device - it feels solid, and that it will last me another five years at minimum.
Hopefully I didn&amp;rsquo;t jinx myself here, though.&lt;/p&gt;
&lt;p&gt;Anyhow, thanks for reading, and please do share your experience with me, or if you know ways of solving the problems I&amp;rsquo;ve listed, I would be glad to know about them!&lt;/p&gt;&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: GNOME is better macOS than macOS&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 23 Nov 2025 02:57:00 +0300</pubDate>
    </item><item>
      <title>Replacing clojure-lsp with clj-kondo and Refactor-nREPL</title>
      <link>https://andreyor.st/posts/2025-09-21-replacing-clojure-lsp-with-clj-kondo-and-refactor-nrepl/</link>
      <guid>https://andreyor.st/posts/2025-09-21-replacing-clojure-lsp-with-clj-kondo-and-refactor-nrepl/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been programming in Clojure for the last five years.
I don&amp;rsquo;t write much about it here, largely because I use Clojure at work and rarely for hobby projects, so I don&amp;rsquo;t have much to share.
Even today, the post will be more about Clojure tooling, rather than Clojure itself.&lt;/p&gt;
&lt;p&gt;Today, most developers expect the language they work with to have a certain amount of specific tools, like a language server, build system, etc.
These tools usually help work on a project with less friction.
For instance, most languages require a language server to provide things like autocomplete, jumping to definition, and linting.
However, when I do work on a hobby project, I usually prefer a more distraction-free environment.
Count me old-school, but I kinda like the simplicity of just having you, your text editor, and the code.
I don&amp;rsquo;t really use these things even with other languages.&lt;/p&gt;
&lt;p&gt;Of course, Clojure itself doesn&amp;rsquo;t need such tooling that much, because there&amp;rsquo;s the REPL, which already acts like your language-specific tooling.
I use Emacs, and it has excellent Clojure support thanks to &lt;a href=&#34;https://nrepl.org/nrepl/index.html&#34; target=&#34;_blank&#34;&gt;nREPL&lt;/a&gt; and &lt;a href=&#34;https://cider.mx/&#34; target=&#34;_blank&#34;&gt;CIDER&lt;/a&gt; - it provides most of the features that a language server can, albeit in a bit different way.
However, even with nREPL and CIDER, I don&amp;rsquo;t really use most of the features, maybe only the goto definition thing.
Another thing provided by language servers is linting, but since Clojure is a dynamic language and it has a REPL, I already evaluate code all the time, so the REPL usually gives me all errors, and I don&amp;rsquo;t really need static linting that much either.&lt;/p&gt;
&lt;p&gt;That goes for hobby projects.
However, when working in a team on a big project, that&amp;rsquo;s a different story.
For the last five years, I&amp;rsquo;ve been working on medium-sized projects, and the main difference for me is that there&amp;rsquo;s a lot of code I didn&amp;rsquo;t write myself.
Language server helps here, because not only does it provide linting of such code, it also allows me to avoid loading all of the code into the REPL for CIDER-specific features to kick in.
Also, not everyone in those projects used a language server, so every now and then the linter pointed out some potential problems.&lt;/p&gt;
&lt;p&gt;Recently, I switched jobs, and now I work on a different team, on a much bigger project.
My work setup didn&amp;rsquo;t change - basically, my Emacs config was ready as is to start working on a new project, or that&amp;rsquo;s what I thought.
However, I noticed that things didn&amp;rsquo;t work out as planned.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a firm believer that developers should use the slowest hardware they can get their hands on for developing.
If your hardware is slow, you&amp;rsquo;re urged to write optimal code and, subsequently, create tools that work on that hardware.
This is where things started to go haywire.&lt;/p&gt;
&lt;p&gt;You see, this is a big project, with a &lt;strong&gt;lot&lt;/strong&gt; of files.
Usually, that&amp;rsquo;s not a problem, however, this time it was.
In Clojure, we have Clojure-LSP as the language server to use.
I have a pretty old laptop.
Here are my specs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;RAM&lt;/th&gt;
&lt;th&gt;CPU&lt;/th&gt;
&lt;th&gt;GPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lenovo IdeaPad S540&lt;/td&gt;
&lt;td&gt;16 GB, 8GB ZRAM SWAP&lt;/td&gt;
&lt;td&gt;AMD Ryzen™ 7 3750H&lt;/td&gt;
&lt;td&gt;AMD Radeon™ Vega 10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It was plenty for anything I did in the past, for hobby projects, that is.
At my previous workplace, I had a work laptop that had 24GB of RAM and a slightly faster CPU.
Not that I really need an extra eight GB of RAM, I never saw it go above 16 while working on a single project.
Sometimes I did work on several projects at the same time, and then it surely helped, but it was rarely the case.&lt;/p&gt;
&lt;p&gt;At the current job, I hit SWAP all the time, and it started to bother me a lot lately.
The reason is, as you might have guessed is Clojure-LSP.
When started in the project I&amp;rsquo;m working on, it alone takes up around 8-11 GB of RAM.
Right now, as I write this post, my editor, Firefox, and a messenger already take up 4.5 GB of RAM, so adding Clojure-LSP to this mix will by itself approach my limit.
And then, I start the REPL, which took another 2-3 GB, and we&amp;rsquo;re in the SWAP territory.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s obvious that there&amp;rsquo;s no way my laptop can handle this load without becoming sluggish.
RAM isn&amp;rsquo;t the only bottleneck here, CPU usage spikes up a lot, too, and the temperature is around 75 degrees and up constantly.
So I decided to change this.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not alone at this, unfortunately, my colleagues also suffer from Clojure-LSP being a resource hog.
And the real problem is that they have even faster machines than mine with more RAM.
So even if I upgrade my laptop or buy a new one, it won&amp;rsquo;t help that much.
So, as an experiment, we decided to disable Clojure-LSP and go back to a simpler setup.&lt;/p&gt;
&lt;h2 id=&#34;disabling-clojure-lsp&#34;&gt;Disabling Clojure-LSP&lt;/h2&gt;
&lt;p&gt;I use the lsp-mode package, so disabling Clojure-LSP was as easy as commenting out the hook that starts the language server, but I went further and &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/commit/a1fda60e7a8e60ffe29ec7bca6e05804285920f2&#34; target=&#34;_blank&#34;&gt;removed lsp-mode completely&lt;/a&gt;, as I don&amp;rsquo;t have use for it other than for Clojure.
But now, I have no linting, which I&amp;rsquo;d like to have since this is a complex project.
The go-to linter in Clojure world is &lt;a href=&#34;https://github.com/clj-kondo/clj-kondo&#34; target=&#34;_blank&#34;&gt;clj-kondo&lt;/a&gt;, so I added &lt;a href=&#34;https://github.com/turbo-cafe/flymake-kondor&#34; target=&#34;_blank&#34;&gt;flymake-kondor&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, since I use &lt;code&gt;flymake&lt;/code&gt; and not &lt;code&gt;flycheck&lt;/code&gt;.
Fortunately, Clojure-LSP uses &lt;code&gt;clj-kondo&lt;/code&gt; internally, so the linting configuration is the same.&lt;/p&gt;
&lt;p&gt;I was expecting that linting such a big project would still eat a lot of RAM, however, for some reason, there wasn&amp;rsquo;t any major spike in RAM usage when just using &lt;code&gt;clj-kondo&lt;/code&gt;.
Linting works fast, and Emacs no longer freezes every now and then.
I guess communication with the language server is much more taxing than simple parsing of &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, linting isn&amp;rsquo;t the only thing provided by Clojure-LSP.&lt;/p&gt;
&lt;h2 id=&#34;bringing-back-refactoring&#34;&gt;Bringing back refactoring&lt;/h2&gt;
&lt;p&gt;Two main things I noticed I rely on with a language server are symbol renaming and finding references.
Both of these tasks can be handled with &lt;code&gt;refactor-nrepl&lt;/code&gt;, however, it&amp;rsquo;s a bit finicky.&lt;/p&gt;
&lt;h3 id=&#34;symbol-renaming&#34;&gt;Symbol renaming&lt;/h3&gt;
&lt;p&gt;Before we begin, let me tell you why you might want this feature as part of the tool that does code analysis.
Sure, it&amp;rsquo;s one thing to rename a symbol inside a single namespace, but when you want to rename it across the project, it gets tricky.&lt;/p&gt;
&lt;p&gt;One way of doing it is to use &lt;code&gt;grep&lt;/code&gt;, and utilize the Emacs capabilities to edit the buffer created by &lt;code&gt;grep&lt;/code&gt; directly.
While it works, it&amp;rsquo;s not as precise as with a language server, because the symbol can be different depending on a file.
For instance, when renaming a namespaced keyword, you can encounter a problem that the keyword is written as &lt;code&gt;::foo&lt;/code&gt; in the file you&amp;rsquo;re editing, but as &lt;code&gt;:fully.qualified.namespace.name/foo&lt;/code&gt; or &lt;code&gt;::namespace-alias/foo&lt;/code&gt; depending on how the namespace was used.
Sure, you can write a regular expression for &lt;code&gt;grep&lt;/code&gt; in the first case, but not really for the second one.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example: imagine we have several namespaces in our project (can be in different files, can be in a single file like here):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; src/project/multimethods.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.multimethods&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; src/project/utils.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.utils&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ,,,)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; src/project/other_ns.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.other-ns&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.multimethods&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.utils&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:refer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.multimethods/a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:project.multimethods/foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; src/project/another_ns.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.another-ns&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.multimethods&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mm&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mm/b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::mm/foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ,,,)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; src/project/unrelated.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.unrelated&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ,,,)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; src/project/yet_another_ns.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.yet-another-ns&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project.unrelated&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unrelated&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::unrelated/foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit verbose, but I tried to make as short of an example that shows all possible ways to use a symbol.
Here, if you&amp;rsquo;re going to rename the &lt;code&gt;::foo&lt;/code&gt; keyword, you can&amp;rsquo;t really grep with &lt;code&gt;&amp;quot;::foo|:project.multimethods/foo|::[^/]+/foo&amp;quot;&lt;/code&gt;, because it will also find &lt;code&gt;::unrelated/foo&lt;/code&gt;, which is &lt;em&gt;unrelated&lt;/em&gt;.
Sure, you can write a pretty generic regular expression, and then meticulously find all relevant symbols in the &lt;code&gt;grep&lt;/code&gt; buffer, and rename them using multiple cursors, or the query-replace feature, but it&amp;rsquo;s a bit much.&lt;/p&gt;
&lt;p&gt;Same goes for renaming functions - if you&amp;rsquo;re trying to rename &lt;code&gt;foo&lt;/code&gt; from &lt;code&gt;project.utils&lt;/code&gt;, grepping can find &lt;code&gt;foo&lt;/code&gt; in the &lt;code&gt;project.unrelated&lt;/code&gt; namespace.
So &lt;code&gt;grep&lt;/code&gt; is not a suitable alternative to Clojure-LSP, as it isn&amp;rsquo;t capable of doing semantic analysis.&lt;/p&gt;
&lt;p&gt;Since we&amp;rsquo;ve disabled Clojure LSP, we need a different tool to handle this task.
Thankfully, there&amp;rsquo;s the &lt;a href=&#34;https://github.com/clojure-emacs/refactor-nrepl&#34; target=&#34;_blank&#34;&gt;refactor-nrepl&lt;/a&gt; project that provides refactoring features via the nREPL integration that we&amp;rsquo;re using.
It has a lot of features, and it works well enough for our project.
&lt;em&gt;Well enough&lt;/em&gt;, because &lt;code&gt;refactor-nrepl&lt;/code&gt; is a bit finicky.&lt;/p&gt;
&lt;h4 id=&#34;problems-with-refactor-nrelp&#34;&gt;Problems with &lt;code&gt;refactor-nrelp&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;First of all, &lt;code&gt;refactor-nrepl&lt;/code&gt; works.
Most of the time, that is.&lt;/p&gt;
&lt;p&gt;I think one of the reasons why Clojure LSP used so much RAM was that it did all of the possible analysis in the background.
The reason I think it&amp;rsquo;s true is that it did the renaming almost instantaneously.&lt;/p&gt;
&lt;p&gt;When renaming a symbol with &lt;code&gt;refactor-nrepl&lt;/code&gt;, I often get a timeout error with CIDER - renaming is a blocking operation, and CIDER tries not to block the editor for too long in some cases.
On a large project, renaming a symbol takes a lot of time to fetch all symbol occurrences alone.
I guess that&amp;rsquo;s the trade-off.
Perhaps I can configure the timeout to be a bit longer, but we&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;Another feature of Clojure LSP I relied on was finding usages.
Refactor nREPL gives that in the form of finding references, which, again, works, but is susceptible to the same timeout problem.
And I&amp;rsquo;m not sure if it is as precise as Clojure LSP&amp;rsquo;s one.
CIDER itself also has a feature for finding usages, but it is also &lt;a href=&#34;https://metaredux.com/posts/2019/12/11/hard-cider-find-usages.html&#34; target=&#34;_blank&#34;&gt;finicky in its own way&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I suppose, because Clojure-LSP appeared, fewer people use &lt;code&gt;refactor-nrepl&lt;/code&gt; today than it was before, and the overall advancement in CIDER development may have slowed down because of it.
Looking at GitHub graphs, &lt;code&gt;refactor-nrepl&lt;/code&gt; development started around 2015, and major activity stopped around 2019, precisely when Clojure-LSP was created.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-09-21-replacing-clojure-lsp-with-clj-kondo-and-refactor-nrepl/refactor-nrepl.png&#34;
         alt=&#34;Figure 1: refactor-nrepl&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;refactor-nrepl&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-09-21-replacing-clojure-lsp-with-clj-kondo-and-refactor-nrepl/clojure-lsp.png&#34;
         alt=&#34;Figure 2: clojure-lsp&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;clojure-lsp&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Which is a bit of a shame, if Clojure-LSP was responsible for slowing down advancement in &lt;code&gt;refactor-nrepl&lt;/code&gt;, but thankfully it is still maintained and works.
It&amp;rsquo;s good to have alternatives, and putting all eggs into one basket was never a good way of doing things.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;refactor-nrepl&lt;/code&gt;, most of the things I used Clojure LSP are again available to me, but I have to do further testing, because I found some instances where it fails.
Maybe I need to configure a bunch of settings.
Or maybe you&amp;rsquo;ll see another post with me going back to Clojure LSP in a few months/weeks.
Who knows!&lt;/p&gt;
&lt;h2 id=&#34;not-a-bashing-on-clojure-lsp&#34;&gt;Not a bashing on Clojure LSP&lt;/h2&gt;
&lt;p&gt;Contrary to what this post may seem like, this was not intended as bashing on Clojure LSP developers.
Clojure LSP is a good piece of tech, and certainly helps Clojure developers around the world.&lt;/p&gt;
&lt;p&gt;The reason it is problematic to use on this particular project can be due to a lot of factors.
First, the project is enormous, lsp-mode reports that it wants to &amp;ldquo;watch&amp;rdquo; for around 2300 directories.
Disabling file watchers helps, but by a small margin.&lt;/p&gt;
&lt;p&gt;Second, the tech stack.
Clojure LSP is written in Clojure, which, while it makes sense, might not be the best choice.
Clojure is known to be not the best tool for writing utilities.
And while Clojure LSP is a server, and not a CLI utility with a fast lifecycle, it may still be sub-optimal.
Maybe, once &lt;a href=&#34;https://jank-lang.org/&#34; target=&#34;_blank&#34;&gt;Jank&lt;/a&gt; is ready, Clojure LSP could be rewritten in it, making it faster.
I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;A completely unrelated reason, in my opinion, is that Clojure itself is not the best target for LSP.
It&amp;rsquo;s a dynamic language, where we do a lot at runtime in the REPL.
Doing static analysis in such a system can be difficult, as there&amp;rsquo;s no longer one source of truth.
nREPL, bridging runtime and source code, while also having a lot of LSP features, seems like a much better fit for languages like Clojure.
And, like, nREPL has appeared almost six years before the Language Server Protocol, and in my opinion, it could have been a far better protocol for developing language tooling, especially since it is also language-agnostic.&lt;/p&gt;
&lt;p&gt;Anyway, replacing Clojure LSP with plain clj-kondo brought back the joy of writing Clojure, so I&amp;rsquo;m happy again.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;What&amp;rsquo;s up with the name? Why not just &lt;code&gt;flymake-kondo&lt;/code&gt;?&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Replacing clojure-lsp with clj-kondo and Refactor-nREPL&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 21 Sep 2025 21:52:00 +0300</pubDate>
    </item><item>
      <title>Implementing SSE with fnl-http and async.fnl</title>
      <link>https://andreyor.st/posts/2025-07-30-implementing-sse-with-fnl-http-and-asyncfnl/</link>
      <guid>https://andreyor.st/posts/2025-07-30-implementing-sse-with-fnl-http-and-asyncfnl/</guid>
      <description>&lt;p&gt;Some time ago, I was working on an HTTP library for Fennel.
As a proof of concept, I added a module that implements a simple web server and wanted to experiment with it.
The server can serve files from a directory using this simple handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:GET&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 404 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not found&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 405
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Method not allowed&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This handler is simple - when the client sends a &lt;code&gt;GET&lt;/code&gt; request with a given path, for example &lt;code&gt;GET http://localhost:8080/some/file.txt&lt;/code&gt;, the handler simply removes the leading &lt;code&gt;/&lt;/code&gt; and tries to open the given path as a file handle.
If the file is present, we return it as is, and the server will handle the closure of this file once the client disconnects.
Otherwise, we return a table with the &lt;code&gt;404&lt;/code&gt; status code, indicating that the file wasn&amp;rsquo;t found.
Other methods are not allowed, and we respond with a &lt;code&gt;405&lt;/code&gt; error by matching on &lt;code&gt;method&lt;/code&gt; with &lt;code&gt;case&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can require the &lt;code&gt;server&lt;/code&gt; module and start a small file-serving server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.server&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server.start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 8080}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:wait&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;(s:wait)&lt;/code&gt; call simply locks the current thread because, without it, the process will just exit.&lt;/p&gt;
&lt;p&gt;This is, of course, the simplest web server there is; it just accesses files in the current directory, returning them as &lt;code&gt;application/octet-stream&lt;/code&gt;.
The handler function can be more sophisticated, handling different methods, parsing arguments, etc.
For our purposes today, we won&amp;rsquo;t need most of these features, but I thought it would be better to familiarize you with how the server is set up.&lt;/p&gt;
&lt;p&gt;The topic of today&amp;rsquo;s post is Server-Sent Events, or SSE for short.
It is a protocol for communicating between a server and multiple clients that uses a persistent connection and pushes messages from the server to the client.
The client can then process these messages at their own pace and react accordingly.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll need an asynchronous library to handle SSE for multiple clients, so let&amp;rsquo;s add it to the mix:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.async&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;alts!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.json&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve also included a JSON library; both are already used by &lt;code&gt;fnl-http&lt;/code&gt;.
Now, let&amp;rsquo;s begin!&lt;/p&gt;
&lt;h3 id=&#34;sse-stream&#34;&gt;SSE stream&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll send events to our clients via a channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This event channel will be our main way to send events to the clients, but we won&amp;rsquo;t read from it directly.
Instead, we can create a &amp;ldquo;publication&amp;rdquo; or &lt;code&gt;pub&lt;/code&gt; that will allow clients to subscribe to the messages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-pub&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-ch&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sse&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.sliding-buffer&lt;/span&gt; 100)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the purposes of this post, there&amp;rsquo;s only one type of message in this &lt;code&gt;event-pub&lt;/code&gt; thing, but in a more complex scenario, you can separate messages and subscribe to different topics altogether.
Speaking of subscribing, here&amp;rsquo;s a helper function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subscribe-to-events&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client-ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-pub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client-ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we need a function to register an event:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-event&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the fun part.
Right now, our event system is ready to be accessed by clients, but the events themselves don&amp;rsquo;t make any sense, as they&amp;rsquo;re just some objects.
We&amp;rsquo;ll define events as tables with the following structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;optional event type&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;optional event id&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;event data&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since our &lt;code&gt;register-event&lt;/code&gt; function simply writes to the &lt;code&gt;event-ch&lt;/code&gt;, we need a way to intercept that.
We can do so by writing middleware that accepts a channel with events as tables and returns a new channel that will have all of the events formatted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-format-sse-event&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;event: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;id: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;event: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;data: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, the general mechanism is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When a client connects, we create a channel and subscribe to events.&lt;/li&gt;
&lt;li&gt;We wrap this channel with our formatter and some other middleware if needed.&lt;/li&gt;
&lt;li&gt;Finally, we return this channel as the response body.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before we write an HTTP handler that does this, we need to consider one other thing: the connection.
If the connection is not used for a long time, it can be closed automatically.
Because of that, it is common to send meaningless heartbeat events every now and then.
Let&amp;rsquo;s write another wrapper that will track if the client&amp;rsquo;s event stream doesn&amp;rsquo;t have any events for some time and return a heartbeat:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-heartbeat&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout-ms&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tout&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout-ms&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;alts!&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tout&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;heartbeat&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; 0})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Similarly to our previous wrapper, we accept a channel with events and return a new channel.
The asynchronous &lt;code&gt;go-loop&lt;/code&gt;, which I didn&amp;rsquo;t mention before, will run in a separate virtual thread, trying to read from both the given channel and a timeout channel.
Whichever returns first will determine what event will be sent to the client.
If a normal event comes through, we send it to the &lt;code&gt;out&lt;/code&gt; channel as is and restart the timer.
If no events come and our timer has been exhausted, we send a heartbeat and restart the timer again.
If our events channel returns &lt;code&gt;nil&lt;/code&gt;, it means that it was closed, so we also close the &lt;code&gt;out&lt;/code&gt; channel.&lt;/p&gt;
&lt;p&gt;Finally, we can implement our handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/events&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:GET&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;events&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subscribe-to-events&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;events&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/event-stream&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;events&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-heartbeat&lt;/span&gt; 10&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-format-sse-event&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/notify&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:POST&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Content-Length&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.decode&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed Content-Lenght&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 405
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.encode&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Method not allowed&amp;#34;&lt;/span&gt;})}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This handler has two main entry points: &lt;code&gt;/events&lt;/code&gt; and &lt;code&gt;/notify&lt;/code&gt;.
The &lt;code&gt;/events&lt;/code&gt; entry is for subscribing to the events stream with a &lt;code&gt;GET&lt;/code&gt; request.
The &lt;code&gt;/notify&lt;/code&gt; entry is for sending events from the client to the server (because right now we don&amp;rsquo;t want to make the server too complicated to generate events on its own).&lt;/p&gt;
&lt;p&gt;Same as before, we can start a server:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server.start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 12345}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:wait&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;reading-the-event-stream-and-triggering-events&#34;&gt;Reading the event stream and triggering events&lt;/h3&gt;
&lt;p&gt;With the server up and running, we can connect a pair of clients.&lt;/p&gt;
&lt;p&gt;The first client will subscribe to the event stream by executing a &lt;code&gt;GET&lt;/code&gt; request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://localhost:12345/events&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we look at the response, we&amp;rsquo;ll see the headers containing &lt;code&gt;text/event-stream&lt;/code&gt; as the content type, as per the response from our server, and the body as a stream, as requested by the client:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564ae85ca7d0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/event-stream&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunked&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x564ae812fa10&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can consume events with a helper function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consume-events&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.insert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt; []]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.date&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]\t&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buf&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consume-events&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the process output, we&amp;rsquo;ll be able to see heartbeat events appearing every ten seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:35 2025]	event: heartbeat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:45 2025]	data: 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:45 2025]	event: heartbeat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:34:55 2025]	data: 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we can send a &lt;code&gt;POST&lt;/code&gt; request from another process, sending an event:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.json&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://localhost:12345/notify&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.encode&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;client-2&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hi from client-2&amp;#34;&lt;/span&gt;})})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We immediately see the event in the first client&amp;rsquo;s output, followed by heartbeat events:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	event: message
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	id: client-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	data: Hi from client-2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:03 2025]	event: heartbeat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Wed Jul 30 00:35:13 2025]	data: 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the time when the heartbeat event arrived is exactly ten seconds after the last non-heartbeat event.
Of course, we can connect multiple clients subscribed to the event stream, and they will all receive events.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/h2&gt;
&lt;p&gt;This should give you an idea of how to implement an SSE stream in your server using the &lt;code&gt;fnl-http&lt;/code&gt; library.
Of course, this implementation is only loosely based on the specification, so I wouldn&amp;rsquo;t suggest it as a general implementation guide, but I hope it provides a clear enough explanation of how things work.&lt;/p&gt;
&lt;p&gt;The server module is still very much in a proof-of-concept stage, but as this article shows, it is working quite well.
All in all, I believe the ability to return an asynchronous channel as a body from the server is a nice way to handle this kind of event system.
The code can be written as usual, and no specific handling for returning asynchronous data via HTTP is required.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I hope you&amp;rsquo;ll find &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; interesting enough to try!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;As much as I don&amp;rsquo;t like &amp;ldquo;Conclusion&amp;rdquo; as the last heading in an article, I can&amp;rsquo;t think of a different one here.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Implementing SSE with fnl-http and async.fnl&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 30 Jul 2025 01:05:00 +0300</pubDate>
    </item><item>
      <title>Effects of Slow and Fast systems</title>
      <link>https://andreyor.st/posts/2025-06-14-effects-of-slow-and-fast-systems/</link>
      <guid>https://andreyor.st/posts/2025-06-14-effects-of-slow-and-fast-systems/</guid>
      <description>&lt;p&gt;Modern-day computing is fast.
&lt;strong&gt;Incredibly fast&lt;/strong&gt;!
For most tasks, the feedback can be considered instantaneous.
Even the slowest languages used in production, like Python, are considered fast enough for the majority of tasks, and if not, there are almost always faster alternatives you could choose from.&lt;/p&gt;
&lt;p&gt;Modern-day CPUs are speedy boys indeed, but it&amp;rsquo;s not just CPUs that are great.
RAM too is no longer a major bottleneck both in terms of size and speed, and even storage is incredibly fast.
GPUs can do millions of tasks under a millisecond in parallel.
Hardware these days is purely amazing.&lt;/p&gt;
&lt;p&gt;Because it&amp;rsquo;s so great, software engineers can do their job much more comfortably, choosing languages with nicer abstractions, and quality-of-life features like automatic garbage collection.
Sometimes, a small trade-off in execution speed is massively outweighed by the robustness that managed languages provide.
I myself am a big fan of advanced virtual machines like the JVM and LuaJIT - they can be both incredibly fast and give you a lot of freedom of expression.&lt;/p&gt;
&lt;p&gt;However, this wasn&amp;rsquo;t always the case.
In the old days, computers were slower.
&lt;strong&gt;Incredibly slower&lt;/strong&gt;!
Today&amp;rsquo;s CPU can process lots of instructions per second.
The execution speed is usually measured in MIPS - Million Instructions Per Second.
For instance, 2021 Intel Core i7 346,350 MIPS - &lt;strong&gt;three hundred forty-six billion three hundred fifty million&lt;/strong&gt; instructions &lt;strong&gt;per second&lt;/strong&gt;, running at 4.92 GHz frequency.
In 1978 Intel 8086 could only process 330,000 instructions per second running at 5.000 MHz&lt;sup&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Instructions_per_second#Timeline_of_instructions_per_second&#34;&gt;source&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We all know this story, about Moore&amp;rsquo;s law, that the number of transistors in an integrated circuit doubles about every two years, and how it is slowed in around 2010.
But while it was going strong, computers became faster and faster every few years.
Computer efficiency is another thing that improved over the years:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-06-14-effects-of-slow-and-fast-systems/Computing_efficiency.png&#34;
         alt=&#34;Figure 1: Computer processing efficiency, measured as the power needed per million instructions per second (watts per MIPS)&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Computer processing efficiency, measured as the power needed per million instructions per second (watts per MIPS)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Perhaps, you already understand, where I&amp;rsquo;m going with this.
Hardware has gotten so much faster over the years we no longer have to wait for the majority of tasks to be completed.
Consequently, the feedback loop for software development shortened dramatically.
So today I want to talk about the implications of working with horribly slow and incredibly fast systems.&lt;/p&gt;
&lt;h2 id=&#34;fast-systems&#34;&gt;Fast systems&lt;/h2&gt;
&lt;p&gt;First, a word about the term &amp;ldquo;system&amp;rdquo; I&amp;rsquo;m using for this post.
I&amp;rsquo;m not talking about operating systems, rather I use this term more broadly.
A particular language can be a system in the context of this text.
Or an entire environment starting from your personal machine, network, remote server, and your tooling of choice and workflow revolving around all of this can also be considered a system here.
Or more broadly - a system is something you interact with &lt;em&gt;systematically&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s look at a few fast systems and implications of their use.&lt;/p&gt;
&lt;h3 id=&#34;interactive-coding&#34;&gt;Interactive coding&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m a Clojure programmer.
So I have a high value for fast feedback during the development process - I can run code in the &lt;abbr title=&#34;Read Eval Print Loop&#34;&gt;REPL&lt;/abbr&gt; at any time and immediately see the effect applied to my running application.
This makes fixing most of the bugs a breeze.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a backend developer, so most of my code runs on a server, not on my machine.
If I were using something else, like Scala or Java, my typical workflow for fixing a bug would probably be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identify a possible wrong place in the codebase&lt;/li&gt;
&lt;li&gt;Change it&lt;/li&gt;
&lt;li&gt;Compile the project&lt;/li&gt;
&lt;li&gt;Deploy it to the remote server&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Restart the service&lt;/li&gt;
&lt;li&gt;Try to reproduce the bug on a running system&lt;/li&gt;
&lt;li&gt;If the bug is not fixed Goto 1&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re good&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With Clojure, my workflow is a bit different:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up SSH port forwarding to the remote server&lt;/li&gt;
&lt;li&gt;Connect to the running application via remote REPL&lt;/li&gt;
&lt;li&gt;Identify a possible wrong place in the codebase&lt;/li&gt;
&lt;li&gt;Change it&lt;/li&gt;
&lt;li&gt;Try to reproduce the bug on a running system&lt;/li&gt;
&lt;li&gt;If the bug is not fixed Goto 3&lt;/li&gt;
&lt;li&gt;Compile the project&lt;/li&gt;
&lt;li&gt;Deploy it to the remote server&lt;/li&gt;
&lt;li&gt;Restart the service&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re good&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While it is a bit longer overall, the feedback loop itself has only three steps, compared to six in the former case.
Thus, I would say that Clojure is a &lt;em&gt;faster system&lt;/em&gt; than Scala or plain Java thanks to the REPL&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; and the ability to change running programs remotely.
The fact that I don&amp;rsquo;t have to wait for compilation, deployment, service restart, and possibly manually setting up some state for bug reproduction after each restart, makes feedback much more immediate.
Thus, I can make almost arbitrary and quite small changes and experiment with real data on live applications until I get things right.
That&amp;rsquo;s what fast systems are good for.&lt;/p&gt;
&lt;h3 id=&#34;notebooks&#34;&gt;Notebooks&lt;/h3&gt;
&lt;p&gt;Ok, so REPL, while being interactive and fast is not the pinnacle of interactivity.
Notebooks, for example, also give you immediate feedback, while also providing a UI for changing the parameters of your computation:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;invertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2025-06-14-effects-of-slow-and-fast-systems/jupiter.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;While this concrete example is kind of slow to respond, it is still a nicer way to get your results faster by dragging a slider instead of changing code directly.
I like the idea of reproducible research papers, where the document itself is the program, I even made something like that with &lt;a href=&#34;https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/&#34;&gt;Org Mode in Emacs and Lua via LÖVE2D&lt;/a&gt;.
It wasn&amp;rsquo;t as interactive, as all of the images are static and require changing the parameters and re-evaluation in the document, but I think it would be possible to make a web version of it by rendering to HTML and connecting to the LÖVE via REPL.&lt;/p&gt;
&lt;p&gt;But why stop there?
Bret Victor years ago showed us an interactive notebook where not only code is interactive, but the results of it are as well!
You can see it for yourself in the talk &lt;a href=&#34;https://www.youtube.com/watch?v=EGqwXt90ZqA&#34; target=&#34;_blank&#34;&gt;Inventing on Principle&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;llm-assisted-coding&#34;&gt;LLM-assisted coding&lt;/h3&gt;
&lt;p&gt;Finally, AI.&lt;/p&gt;
&lt;p&gt;Yes, we&amp;rsquo;re going to talk about &lt;abbr title=&#34;Large Language Model&#34;&gt;LLM&lt;/abbr&gt;-assisted programming, or so-called vibe coding.
I consider it another fast system, because you can get your code changes pretty fast by giving your code to some LLM, and it will spit out a solution for you.
Either incremental changes to your code or additional code written based on your program&amp;rsquo;s context.&lt;/p&gt;
&lt;p&gt;This also makes your feedback loop shorter, because you don&amp;rsquo;t have to write the code yourself.
You can think in higher-order terms, and LLM will hopefully give you what you need.
In the best-case scenario, you won&amp;rsquo;t even touch the code by yourself.&lt;/p&gt;
&lt;p&gt;I think combining Bret Victor&amp;rsquo;s notebook-like system with LLM can be an interesting approach.
Actually, the code for the square wave example above was written by a Claude 3 Haiku model&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;.
I have mixed thoughts on AI and LLM in general, but we&amp;rsquo;re gonna leave it out of the scope of this topic.&lt;/p&gt;
&lt;h4 id=&#34;fast-knowledge-system&#34;&gt;Fast knowledge system&lt;/h4&gt;
&lt;p&gt;Another thing about LLMs is that it is a very compelling search engine that can find information really fast.
Want to learn a new thing?
Ask the LLM about it and it will spit out the essential information.
The quality of such information is a subject for another time, but let&amp;rsquo;s assume that it doesn&amp;rsquo;t hallucinate too much.&lt;/p&gt;
&lt;p&gt;You can learn things fast!
If the thing you&amp;rsquo;re trying to learn is well covered in the training data, it can be much faster than learning from the books.
Especially because a well-trained LLM can answer your questions and provide more examples, unlike any plain ol&amp;rsquo; book.&lt;/p&gt;
&lt;h2 id=&#34;slow-systems&#34;&gt;Slow systems&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s talk about slow systems.
Slow here can mean many things, from the amount of time it takes to do something to the general approach to doing something.&lt;/p&gt;
&lt;h3 id=&#34;slow-hardware&#34;&gt;Slow hardware&lt;/h3&gt;
&lt;p&gt;I started this post by talking about hardware advancement for a reason.&lt;/p&gt;
&lt;p&gt;At the university, my computer science teacher always said that programmers should get the slowest hardware they can find, and do all of the development on it.
He reasoned that if an application can be developed and tested on slow hardware, the end-user experience will be great because their machines would certainly be faster than the ones that were used for development.&lt;/p&gt;
&lt;p&gt;Developing on slower hardware limits you in a way that is hard to get otherwise.
Today&amp;rsquo;s computers can process a lot of data fast, but three decades ago it wasn&amp;rsquo;t possible.
Yet, we could go to the cinema in 1995 and watch such films as Toy Story - a film that was fully CGI.
It took four years to make the film, and a lot of it was just rendering.
Two years earlier, in 1993 Jurassic Park came out, and while it contained a very small amount of computer graphics, a test scene for the film was made before featuring fully computer-generated dinosaurs.
The thing is, each frame took around 12 hours to render back then.
And today we get video games that can look almost photo-real, outputting more than 60 frames in a single second.&lt;/p&gt;
&lt;p&gt;What a horrible time the 90s were for CGI, you might say, and while you&amp;rsquo;d be right, slow hardware also had a positive effect - people had to write extremely fast software to even get barely usable results.
And this software had to be robust too.
When computing is this slow, you can&amp;rsquo;t avoid making a mistake, ruining days or even months of work.&lt;/p&gt;
&lt;p&gt;But today it&amp;rsquo;s not a problem, right?
Hardware is always fast, and we can upgrade it any time.&lt;/p&gt;
&lt;p&gt;Well, not quite.
While computers have become faster, we still have slow hardware that people have to optimize hard for.
Want to try and take a guess which is it?&lt;/p&gt;
&lt;p&gt;Game consoles.&lt;/p&gt;
&lt;p&gt;Yeah, right, the thing that is supposed to be a pinnacle of gaming and graphics on release date slowly becomes obsolete with each year of its life.
New CPUs and GPUs come out every few years, but game developers still have to optimize games for a console that is already a few years old.&lt;/p&gt;
&lt;p&gt;Take a look at early games for Super Nintendo and the late games released for it.
The later games are much more graphically rich than the early ones because while the hardware got older, the ambitions for games only got higher.
And developers had to optimize, even use dirty tricks to pump out graphics like in Super Metroid, for example.&lt;/p&gt;
&lt;p&gt;Or take PlayStation 3.
Some of its late exclusives looked even better than the ones released for PlayStation 4 at launch.
Why?
Because their development started when PlayStation4 was not available, and gamers were getting better and better graphics on their PCs, so PlayStation 3 had to compete with them, not just other consoles.
And slow hardware meant that they couldn&amp;rsquo;t just slap a new Unreal Engine on and expect it to just work - they had to optimize their games for a specific, and somewhat arcane hardware.
And how good these late games looked, especially compared to the launch titles!&lt;/p&gt;
&lt;p&gt;Today we have a problem with a lot of games that release on several platforms at once because game developers often use the top tier hardware for their development process, and then games can&amp;rsquo;t run smoothly on hardware with lower specs that it wasn&amp;rsquo;t optimized for specifically.
Had the developers restricted their hardware limit to the lowest common denominator platform they&amp;rsquo;re targeting,f and thus the urge to optimize their code, maybe consumers could upgrade their hardware less often too, and be happier overall.&lt;/p&gt;
&lt;p&gt;And this isn&amp;rsquo;t just games.
Ordinary software today is as slow as ****.
Like, some time ago the GNOME project replaced their old image viewer with a new one, and its startup time is seemingly ten times slower.
And once it started it couldn&amp;rsquo;t even switch pictures as fast as the old one.
I don&amp;rsquo;t know what kind of computers GNOME developers use, but it seems that lower-spec hardware is not their target.
And don&amp;rsquo;t get me started comparing modern GNOME&amp;rsquo;s speed with GNOME2&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Microsoft Windows sometimes takes a few seconds to show me the menu when I right-click on the desktop.
This is the most basic action you can do, and yet it is so slow.
Maybe if I had a gaming PC with a top-tier CPU, GPU, RAM, and SSD, it would not be so slow, but all I have is a late 2019 laptop with an eight-core AMD Ryzen 7 3750H.
And it packs enough power for almost everything I do, even though it is six years old.&lt;/p&gt;
&lt;h3 id=&#34;slow-tools-and-workflows&#34;&gt;Slow tools and workflows&lt;/h3&gt;
&lt;p&gt;When your hardware is slow, all of your tools are as fast as your hardware allows them to be.
And when you have a slow tool, you don&amp;rsquo;t want to run it more times than is necessary, because you have to wait every time.&lt;/p&gt;
&lt;p&gt;This also applies to workflows.
If your workflow is slow, you don&amp;rsquo;t want to take unnecessary steps, as it would take your precious time.
Going back to the &lt;a href=&#34;#interactive-coding&#34;&gt;Interactive coding&lt;/a&gt; section of this post, let&amp;rsquo;s again look at the workflow for Scala/Java software development:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identify the correct place in your codebase to start working&lt;/li&gt;
&lt;li&gt;Write code&lt;/li&gt;
&lt;li&gt;Compile the project&lt;/li&gt;
&lt;li&gt;Deploy it to the remote server&lt;/li&gt;
&lt;li&gt;Restart the service&lt;/li&gt;
&lt;li&gt;Try to see if it works&lt;/li&gt;
&lt;li&gt;If it doesn&amp;rsquo;t work right goto 2&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re good&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Again, compared to a language with interactive development, like Clojure, it is several steps longer.
The implication of this is that you should, in theory, spend more time thinking about how to approach the task at hand.
You don&amp;rsquo;t want to repeat this scenario over and over making small incremental changes, because compilation, deployment, restarting, and testing take too much time.
So in theory, you should always try to write your code as best as you possibly can.&lt;/p&gt;
&lt;p&gt;This, indeed is what happened in the early days of computing.
Back then, computers operated via punch cards, and people had to submit their code on paper to the card puncher operator, then wait in the queue of other researchers, finally receiving the results printed out by the machine on another piece of paper.
The cost of a mistake in the code was so high, that programmers had to spend a lot of time verifying their code in their head and praying that the operator wouldn&amp;rsquo;t make a typo while transferring your code to the punch card.
The process &lt;strong&gt;demanded&lt;/strong&gt; quality.&lt;/p&gt;
&lt;p&gt;Only later we got machines that could do this in a fraction of time, but it was still slow.
You may be familiar with &amp;ldquo;The Story of Mel, a Real Programmer&amp;rdquo;.
The gist of it was that the machine was using a &lt;a href=&#34;https://en.wikipedia.org/wiki/Drum_memory&#34; target=&#34;_blank&#34;&gt;drum memory&lt;/a&gt;, which was very slow, but instead of accepting it as fact, Melvin Kaye, the protagonist of this story wrote its code in such a way that the program self-modified itself in the time it takes for the drum to revolve, to immediately continue.
This is what basically an optimizing compiler would do, but Mel didn&amp;rsquo;t like the fact that this compiler would produce ugly code, and was still slower than a hand-optimized one.
Somehow, we&amp;rsquo;ve lost this art of coding, but that&amp;rsquo;s another story.&lt;/p&gt;
&lt;p&gt;Going back to slow workflow, we no longer suffer from waiting in the queue to use the computer, but maybe we should?
There&amp;rsquo;s a saying that urgent things are rarely of great importance, and those that are important are seldom of great urgency.
Sometimes it&amp;rsquo;s good to take your time and go and take a seat, thinking about the problem you&amp;rsquo;re solving, and how to solve it well, or even leave it to the subconscious thinking and step away from it entirely&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.
The dread of waiting in the queue for several days can easily force you into such behavior.&lt;/p&gt;
&lt;h3 id=&#34;slow-knowledge-system&#34;&gt;Slow knowledge system&lt;/h3&gt;
&lt;p&gt;In the &lt;a href=&#34;#fast-knowledge-system&#34;&gt;AI section&lt;/a&gt; I&amp;rsquo;ve touched on the learning aspect of using LLMs.
While you indeed can get a lot of information fast, sometimes it&amp;rsquo;s better to take it slow.
Slow learning is not bad, if you&amp;rsquo;re digging deep.&lt;/p&gt;
&lt;p&gt;Sometimes, when I&amp;rsquo;m learning a new thing, I find myself reading books, sometimes even several times.
By the time I&amp;rsquo;ve finished, I have a deep understanding of the subject and can reason about it much more thoroughly than I ever could if I just did a quick search or used an LLM to explain stuff to me.
I like the education model at the university - you have lectures that go over the subject in some depth, but then you&amp;rsquo;re given time to go over that same subject at your own pace with a book at home.
That first quick overview gave you enough context to understand a longer-form explanation usually reserved for books so that you have an easier time understanding it.
It takes a lot more time because you have to go over the same material basically twice, but your understanding is far more deep as a result.
If you&amp;rsquo;re a good student, that is.
I wasn&amp;rsquo;t, and now I&amp;rsquo;m sad about it.&lt;/p&gt;
&lt;p&gt;Before the internet, the only way of acquiring knowledge was by going to a library.
If it had the book, then great, but that&amp;rsquo;s all you get.
If not - tough time, maybe you could afford to go to another town with a bigger library, or maybe you could request for your library to acquire a specific book, but that&amp;rsquo;s it.
Today we can get our hands almost at any book we want.&lt;/p&gt;
&lt;p&gt;But this isn&amp;rsquo;t an all-good thing either.
Too many books in our reach can be overwhelming by itself.
Sometimes, I think, it&amp;rsquo;s best when our choice is limited, and if we want to go out of our way to get another book, it is usually because we know that we need it, not because we&amp;rsquo;re bored with the one we have.&lt;/p&gt;
&lt;h2 id=&#34;effects-of-slow-and-fast-systems&#34;&gt;Effects of Slow and Fast systems&lt;/h2&gt;
&lt;p&gt;Times of slow computing are long gone.
But the effects of slow systems are not limited to computing - it&amp;rsquo;s everywhere.
The term system, I used in this article, is a lot wider, and applies to a lot of things.
But today, more faster and faster systems are appearing around us.
This already had an effect on our life.&lt;/p&gt;
&lt;p&gt;For example, long-form content became a rare thing, because our brains have adjusted to the fast form of content consumption, and a lot of people today can&amp;rsquo;t hold their attention for longer than a minute, sometimes less.
A book is a slow system, a course is a faster system, and an article is an even faster one.
They all serve the purpose of providing information.&lt;/p&gt;
&lt;p&gt;I write pretty long posts myself, and I noticed that because it takes a lot of time to write everyone, my attention span improved over these five years of writing.
My workflow is also slow, as I don&amp;rsquo;t have things like live preview of my blog posts, I don&amp;rsquo;t use any automation tools or LLMs, just a basic spellchecker.
Because I re-read my posts a lot, it improved my ability to concentrate - I became able to concentrate more, and now I can read more than I could earlier as a result.&lt;/p&gt;
&lt;p&gt;Old paper mail is a very slow system, engaging longer and more thoughtful forms of conversation.
You wouldn&amp;rsquo;t write &amp;ldquo;Hi! I have a question&amp;rdquo; in a mail, and expect a &amp;ldquo;Hi! What&amp;rsquo;s your question?&amp;rdquo; as a response.
Email is a faster system, but still a rather slow one, when compared to more modern chats.
But a lot of people today have forgotten how to write long and concise messages because faster systems have been around for so long.&lt;/p&gt;
&lt;p&gt;I have high respect for communities, where people can respond to each other with thoughtful thought heavy messages.
That&amp;rsquo;s also the reason I&amp;rsquo;m using email as a comment system for my blog - I doubt many people would want to write a long comment to my post if it was a web form, but when given an email as the feedback system, they subconsciously try to give it more thought.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t get me wrong though, I&amp;rsquo;m not advocating that we should abandon advancements in hardware and infrastructure and go to simpler times.
No, of course not!
I too enjoy faster systems, I like interactive programming, fast feedback, and such.
I have a lot of fond memories of late-night chatting in fast-paced group chats, and I definitively don&amp;rsquo;t want all of my communication to be done via email only.
Sometimes I want to ask about things I know nothing of, instead of searching through books or papers.
I just think that sometimes slowing down is the thing you need, but we rarely think about it.
When everyone around you is all about &amp;ldquo;Go! Go! Go!&amp;rdquo;, it is tough to rise and say &amp;ldquo;Hold on, I need to take it slow&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;It&amp;rsquo;s not a production, but a test server.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I know that Scala REPL is a thing, but nobody in our team uses it like this.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Not that I couldn&amp;rsquo;t write it myself, I just don&amp;rsquo;t know how to use Jupiter and am not familiar enough with Python&amp;rsquo;s matplotlib.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Even though GNOME got a lot faster over the years since the original GNOME Shell release.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=f84n5oFoZBc&#34; target=&#34;_blank&#34;&gt;Hammock Driven Development&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Effects of Slow and Fast systems&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 14 Jun 2025 04:22:00 +0300</pubDate>
    </item><item>
      <title>Implementing dynamic scope for Fennel and Lua</title>
      <link>https://andreyor.st/posts/2025-06-09-implementing-dynamic-scope-for-fennel-and-lua/</link>
      <guid>https://andreyor.st/posts/2025-06-09-implementing-dynamic-scope-for-fennel-and-lua/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m continuing my work on &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;, my port of &lt;code&gt;clojure.core&lt;/code&gt; and some other core libraries, focusing on porting missing functions and features to it.
One such feature, which I sometimes miss in Lua and Fennel, is &lt;a href=&#34;https://en.wikipedia.org/wiki/Scope_%28computer_science%29#Dynamic_scope&#34; target=&#34;_blank&#34;&gt;dynamic binding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Lua VM doesn&amp;rsquo;t provide dynamic scoping as a language feature, and Fennel itself doesn&amp;rsquo;t introduce any concepts like Clojure&amp;rsquo;s &lt;code&gt;Var&lt;/code&gt;.
However, we can still implement dynamic scoping that works similarly to Clojure and other Lisps using the &lt;code&gt;debug&lt;/code&gt; library.
Most of the ideas are based on information from the &lt;a href=&#34;https://leafo.net/guides.html&#34; target=&#34;_blank&#34;&gt;guides&lt;/a&gt; at &lt;a href=&#34;https://leafo.net/&#34; target=&#34;_blank&#34;&gt;leafo.net&lt;/a&gt;.
There&amp;rsquo;s even a &lt;a href=&#34;https://leafo.net/guides/dynamic-scoping-in-lua.html&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Dynamic scoping in Lua&amp;rdquo;&lt;/a&gt; guide that implements a slightly different version of this feature, requiring variables to be referenced by name via &lt;code&gt;dynamic(&amp;quot;var_name&amp;quot;)&lt;/code&gt; call.
While this approach is feasible, I wanted something more in line with how other Lisps work, so let&amp;rsquo;s explore advancing it further.
Luckily for us, Leafo already has all the necessary guides!&lt;/p&gt;
&lt;p&gt;But first things first.
I wanted to delay working on dynamic scoping as much as possible because it is a feature that&amp;rsquo;s hard to get right.
I already have some experience with implementing dynamic scoping for one of my older libraries that implemented a &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-conditions&#34; target=&#34;_blank&#34;&gt;condition system&lt;/a&gt; from Common Lisp in Fennel.
This library, however, required special syntax to access all of the dynamically bound symbols and thus did not actually require anything fancy for it to work.&lt;/p&gt;
&lt;p&gt;So what does dynamic binding/scoping mean in a language?
If you know about lexical and dynamic scoping and wish to skip this tangent, feel free to &lt;a href=&#34;#implementing-dynamic-scope-in-fennel&#34;&gt;do so&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short, lexically scoped variables exist only where their lexical scope allows them to.
For example, a variable defined in a block of code will only exist in that block because it is its lexical scope.&lt;/p&gt;
&lt;p&gt;When working with languages that have higher-order functions, I often find myself in a situation where I want to refactor some code that uses anonymous functions by moving them out and giving them a name.
Sometimes it&amp;rsquo;s possible; sometimes it&amp;rsquo;s not.&lt;/p&gt;
&lt;p&gt;For example, imagine I wanted to move out this function from &lt;code&gt;map&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I were to do so, we would have a problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; oops, extra-data is now an unknown variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So &lt;code&gt;extra-data&lt;/code&gt; is bound lexically, and thus if we look at the lexical scope of the &lt;code&gt;process-messages&lt;/code&gt; function, we&amp;rsquo;ll see that it tries to use &lt;code&gt;extra-data&lt;/code&gt; while it&amp;rsquo;s not defined there.
If &lt;code&gt;extra-data&lt;/code&gt; were a global variable, it wouldn&amp;rsquo;t be problematic, but it is a local variable with a lexical scope.
We could move the entire &lt;code&gt;let&lt;/code&gt; that binds &lt;code&gt;extra-data&lt;/code&gt; to the result of calling &lt;code&gt;other-func&lt;/code&gt;, but let&amp;rsquo;s say we don&amp;rsquo;t want to call it on each iteration of a &lt;code&gt;map&lt;/code&gt; because it&amp;rsquo;s slow and will do the same work repeatedly.
So, what are our options here?&lt;/p&gt;
&lt;p&gt;Well, we can make it a closure!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-message-processor&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-message-processor&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we pass &lt;code&gt;extra-data&lt;/code&gt; only once to the &lt;code&gt;make-message-processor&lt;/code&gt; function, and it returns a function that has this variable stored in a closure.
However, this is still a lexical scope because, as you can see, &lt;code&gt;extra-data&lt;/code&gt; is present there.&lt;/p&gt;
&lt;p&gt;In a language that uses dynamic scoping, this could be a whole different story.
Let&amp;rsquo;s look at Clojure; although I wouldn&amp;rsquo;t recommend doing it this way, it is possible to do it this way&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do-stuff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-func&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other-func&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;messages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, I assume that &lt;code&gt;extra-data&lt;/code&gt; is a dynamic variable that obeys the rules of dynamic scoping.
The &lt;code&gt;binding&lt;/code&gt; call introduces a dynamic scope within which &lt;code&gt;extra-data&lt;/code&gt; is set to the value of &lt;code&gt;(other-func)&lt;/code&gt;.
It acts more like a scoped global variable, or at least you can think of it that way.&lt;/p&gt;
&lt;p&gt;To introduce a dynamic scope, Clojure uses &lt;code&gt;binding&lt;/code&gt;.
Let&amp;rsquo;s look at it briefly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;binding =&amp;gt; var-symbol init-expr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  Creates new bindings for the (already-existing) vars, with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  supplied initial values, executes the exprs in an implicit do, then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  re-establishes the bindings that existed before.  The new bindings
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  are made in parallel (unlike let); all init-exprs are evaluated
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  before the vars are bound to their new values.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:added&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-args&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vector? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a vector for its binding&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;an even number of forms in binding vector&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-ize&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-vals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-vals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt; `(&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;~(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;))) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;second &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vvs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;push-thread-bindings&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;hash-map &lt;/span&gt;~@(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var-ize&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ~@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pop-thread-bindings&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a simple idea: a &lt;code&gt;try&lt;/code&gt; block without &lt;code&gt;catch&lt;/code&gt; statements, only with a &lt;code&gt;finally&lt;/code&gt; clause.
Before we enter the &lt;code&gt;try&lt;/code&gt; block, we set all mentioned variables to their values, and after we&amp;rsquo;re done with the &lt;code&gt;body&lt;/code&gt;, we restore those values.&lt;/p&gt;
&lt;p&gt;In Clojure, dynamic bindings work really well, but this is due to a combination of factors.
First, the &lt;code&gt;try&lt;/code&gt; support in the JVM is excellent, ensuring that &lt;code&gt;finally&lt;/code&gt; will perform its intended function.
Additionally, the JVM supports thread-local bindings, so even in a multithreaded context, &lt;code&gt;binding&lt;/code&gt; still works.
&lt;em&gt;Finally&lt;/em&gt;, heh, Clojure has Vars, which makes it all possible.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s try to implement the same concept in Fennel!&lt;/p&gt;
&lt;h2 id=&#34;implementing-dynamic-scope-in-fennel&#34;&gt;Implementing dynamic scope in Fennel&lt;/h2&gt;
&lt;p&gt;Before I descend into madness, I would say that we could do the same thing as in Clojure: set some variables, run code in a protected call, and reset the variables afterward.
While this approach would indeed work, I wanted to tidy up my understanding of function environments in Lua.
It&amp;rsquo;s a neat concept that Lua and a few other languages have, but Lua is one of the few languages that actually allows users to manipulate function environments.
So, let&amp;rsquo;s explore this idea.&lt;/p&gt;
&lt;p&gt;First, we need a way to forcefully set a function&amp;rsquo;s environment.
This could be done in Lua 5.1 via &lt;code&gt;setfenv&lt;/code&gt;; however, it was removed starting from Lua 5.2 onward.
It can be implemented like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.setfenv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.getupvalue &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:_ENV&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.upvaluejoin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;) 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can set an environment for any function.&lt;/p&gt;
&lt;p&gt;But what exactly is this function environment? I&amp;rsquo;ve realized that I never explained that, so here we go.&lt;/p&gt;
&lt;p&gt;In Lua, the environment is a table&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; that stores the names of the variables.
Starting from Lua 5.2, the environment is represented by a variable called &lt;code&gt;_ENV&lt;/code&gt;, which is what we&amp;rsquo;re testing for in &lt;code&gt;setfenv&lt;/code&gt; above.
By default, &lt;code&gt;_ENV&lt;/code&gt; has the same value as &lt;code&gt;_G&lt;/code&gt;, a table that contains all global variables.
However, we can change the function&amp;rsquo;s environment by modifying the value of &lt;code&gt;_ENV&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For instance, in Lua, we can set &lt;code&gt;_ENV&lt;/code&gt; to a table, and all global definitions would end up in that table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _ENV = t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    a = 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    b = 322
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f(t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(a, b) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 0, nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(t.a, t.b) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 42, 322&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a cool feature, and we can actually use environments for sandboxing code, but that&amp;rsquo;s a story for another time.
Let&amp;rsquo;s return to dynamic scoping.&lt;/p&gt;
&lt;p&gt;Looking at this, you might get the idea that if we change the function&amp;rsquo;s environment and set our dynamic variables in it specifically, once we leave the lexical scope of that &lt;code&gt;_ENV&lt;/code&gt;, all changes revert to normal because they never happened in a global environment!&lt;/p&gt;
&lt;p&gt;Unfortunately, it&amp;rsquo;s not that simple.
Yes, we can change the function&amp;rsquo;s environment, but it will only affect that specific function.
Moreover, this change is permanent, meaning that we&amp;rsquo;ll have to reset the function back to its original environment.
So, it&amp;rsquo;s not as straightforward as just changing &lt;code&gt;_ENV&lt;/code&gt; around the code we want to run.
Of course, we could write &lt;code&gt;getfenv&lt;/code&gt;, then wrap the entire thing in a &lt;code&gt;pcall&lt;/code&gt;, and safely restore the environment once the work is done.&lt;/p&gt;
&lt;p&gt;However, we can&amp;rsquo;t set the environment of just the function we&amp;rsquo;re calling.
&lt;code&gt;_ENV&lt;/code&gt; is stored in a closure, so we&amp;rsquo;ll need to change all of the functions called by the function we wish to invoke with a custom environment.
This makes undoing changes trickier to implement.&lt;/p&gt;
&lt;p&gt;Luckily for us, we can bypass the need to roll back the changes to the function&amp;rsquo;s environment completely!
Instead, we can simply clone the function and set its environment as we wish!
Here&amp;rsquo;s an implementation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clone-function-with-env&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Recursively clones the function `f`, and any subsequent functions that it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;might call via upvalues.  Sets `env` as environment for the cloned function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dumped&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.dump &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;load &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dumped&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.getupvalue &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:function&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clone-function-with-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.setupvalue &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;subf&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;debug.upvaluejoin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setfenv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cloned&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we write the function that will call a given function &lt;code&gt;f&lt;/code&gt; in a context where the given &lt;code&gt;bindings&lt;/code&gt; are dynamically bound:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-call&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Calls `f` with `bindings` as its root environment.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-env&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_ENV&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f*&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clone-function-with-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As well, as a convenience macro for using it like a &lt;code&gt;let&lt;/code&gt; but with dynamic binding:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected a sequence of bindings&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected an even number of forms in binding sequence&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic-call&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt;) 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bindings&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can use dynamic binding in Fennel!&lt;/p&gt;
&lt;h3 id=&#34;usage-example&#34;&gt;Usage example&lt;/h3&gt;
&lt;p&gt;To illustrate, let&amp;rsquo;s create some variables that we wish to treat dynamically:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;global &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 21)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;global &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 73)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 21	73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With globals in place, we can try our &lt;code&gt;binding&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 42 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, &lt;code&gt;foo&lt;/code&gt; no longer refers to &lt;code&gt;21&lt;/code&gt;, but now it is &lt;code&gt;42&lt;/code&gt;.
However, if we try to print &lt;code&gt;foo&lt;/code&gt; outside of &lt;code&gt;binding&lt;/code&gt;&amp;rsquo;s scope, we will again get &lt;code&gt;21&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A keen reader would mention that this example is not so different from using a plain &lt;code&gt;let&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And you&amp;rsquo;d be right!
However, where it&amp;rsquo;s going to be different is when we put functions into the mix:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;How, if we were to call it inside of &lt;code&gt;let&lt;/code&gt;, the bindings introduced by it won&amp;rsquo;t affect the function, because both &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; are not lexically present here:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 1337]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; still prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 21 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is where &lt;code&gt;binding&lt;/code&gt; jumps in.
Instead of following lexical binding rules, that are natural for most languages, we now introduce dynamic binding of &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 1337]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 42 1337&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 21 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, as can be seen above, inside &lt;code&gt;binding&lt;/code&gt;&amp;rsquo;s scope, &lt;code&gt;f&lt;/code&gt; sees &lt;code&gt;foo&lt;/code&gt; as &lt;code&gt;42&lt;/code&gt;, and &lt;code&gt;bar&lt;/code&gt; as &lt;code&gt;1337&lt;/code&gt;, while outside of it, the values are still &lt;code&gt;21&lt;/code&gt; and &lt;code&gt;73&lt;/code&gt;.
So, we never actually changed the values of &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;, they&amp;rsquo;re still &lt;code&gt;21&lt;/code&gt; and &lt;code&gt;73&lt;/code&gt;, respectfully.
Instead, in the scope of &lt;code&gt;binding&lt;/code&gt; we changed how &lt;code&gt;f&lt;/code&gt; accesses these variables.&lt;/p&gt;
&lt;p&gt;This also works with functions that call other functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;g:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;h:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;binding&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; 322]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; g: 322&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; h: 42 322&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s pretty much it!
This approach has a lot of flaws though.&lt;/p&gt;
&lt;p&gt;First, it will only work on ordinary functions, so no tricks with &lt;code&gt;__call&lt;/code&gt; metamethod, or native functions are supported.&lt;/p&gt;
&lt;p&gt;Second, it won&amp;rsquo;t work with coroutines either.
You can&amp;rsquo;t use &lt;code&gt;string.dump&lt;/code&gt; on something like &lt;code&gt;coroutine.resume&lt;/code&gt; directly, so we won&amp;rsquo;t be able to do &lt;code&gt;(dynamic-call {:foo 42} coroutine.resume some-coroutine)&lt;/code&gt;.
It won&amp;rsquo;t even work if we wrap &lt;code&gt;coroutine.resume&lt;/code&gt; into an anonymous function like &lt;code&gt;(dynamic-call {:foo 42} (fn [] (coroutine.resume coro)))&lt;/code&gt;, because &lt;code&gt;coro&lt;/code&gt; here, while being an upvalue, is not a function, so we can&amp;rsquo;t clone it.&lt;/p&gt;
&lt;p&gt;Finally, it relies on the &lt;code&gt;debug&lt;/code&gt; library, and recursive function dumping, which itself is already pretty crazy.&lt;/p&gt;
&lt;p&gt;There are probably more things that can go wrong with this.&lt;/p&gt;
&lt;h2 id=&#34;so-why-not-just-set-the-globals-temporarily&#34;&gt;So why not just set the globals temporarily?&lt;/h2&gt;
&lt;p&gt;First of all, yes, we could just set the globals temporarily, and restore their values later:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-globals&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;collect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;_G &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;_G &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new-val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-val&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-vals&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;old-vals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;_G &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt; 0)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call-with-temp-globals&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;globals&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-globals&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call-with-temp-globals&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; 123 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; 456} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 123&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; g: 456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; f: 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; g: 73&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While this works, I don&amp;rsquo;t like the idea that we&amp;rsquo;re actually changing the values instead of shadowing them in the environment, though this is more akin to the original Clojure implementation.
Since Lua is single-threaded it should not be problematic, however, I think it can still mess things up if we were to introduce some kind of an asynchronous scheduler, like in my &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; library.
This also messes up stacktraces in cases where an error occurs as a result of calling &lt;code&gt;f&lt;/code&gt; because you can&amp;rsquo;t re-throw errors in Lua like in other languages.
There&amp;rsquo;s also a potential to use &lt;code&gt;&amp;lt;close&amp;gt;&lt;/code&gt; marker that came in Lua 5.4 to avoid &lt;code&gt;pcall&lt;/code&gt; altogether:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set_globals&lt;/span&gt;(globals)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; old_values = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; name, new_val &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(globals) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        old_values[name] = _G[name]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _G[name] = new_val
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; old_values
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close_handler&lt;/span&gt;(old_values)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; name, val &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(old_values) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _G[name] = val
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dynamic_call_close&lt;/span&gt;(globals, f, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; old_values &amp;lt;close&amp;gt; =
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        setmetatable(set_globals(globals), {__close = close_handler})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This would keep stack traces intact, and values would be restored right when we exit &lt;code&gt;dynamic_call_close&lt;/code&gt; but will only work in Lua 5.4.&lt;/p&gt;
&lt;p&gt;Thus, while doing it with &lt;code&gt;pcall&lt;/code&gt; is more generic, I wanted to explore the environment approach first since Lua already provides a mechanism for working with function environments.
But for now, I think I&amp;rsquo;ll leave dynamic scoping out of &lt;code&gt;cljlib&lt;/code&gt; as I&amp;rsquo;m not really sold on any of the ways of doing it that I&amp;rsquo;ve come up with so far.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I really don&amp;rsquo;t like this way of refactoring this code, but sometimes it is exactly what you need.
Not this time, though.
The approach with closures is what I&amp;rsquo;d use in this case in Clojure too.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Everything in Lua is a table, because of course it is.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Implementing dynamic scope for Fennel and Lua&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 09 Jun 2025 22:31:00 +0300</pubDate>
    </item><item>
      <title>Am I becoming obsolete or just older?</title>
      <link>https://andreyor.st/posts/2025-04-22-am-i-becoming-obsolete-or-just-older/</link>
      <guid>https://andreyor.st/posts/2025-04-22-am-i-becoming-obsolete-or-just-older/</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s set the tone for this post right away, I just want to get this out of my system: I despise the rise of AI in tech.
Coding assistants, chat-bots, vibe-coding, agents.
Oh, the vibe coding&amp;hellip; WTF?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-04-22-am-i-becoming-obsolete-or-just-older/old_man_yells_at_openai.png&#34;
         alt=&#34;Figure 1: This will be an &amp;amp;ldquo;old man yells at cloud&amp;amp;rdquo; type of post.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;This will be an &amp;ldquo;old man yells at cloud&amp;rdquo; type of post.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I don&amp;rsquo;t like AI in general, although I know that neural networks can be used for good.
Before you accuse me that I&amp;rsquo;m completely anti-AI, let me explain where I see this technology applicable.&lt;/p&gt;
&lt;p&gt;One such example is modeling.
I play guitar, and it&amp;rsquo;s a pretty expensive hobby.
A good guitar itself can cost hundreds, or thousands of dollars, but then there&amp;rsquo;s guitar gear.
Tube amplifiers and pedals are &lt;strong&gt;expensive&lt;/strong&gt;.
Not everyone has money to have several amplifiers for achieving versatile sound, and a bunch of effect pedals to work with these amplifiers.&lt;/p&gt;
&lt;p&gt;The industry noticed that, and a lot of effort was put into modeling these circuits in software.
Guitar pedals and amplifiers are basic electronics, for the most part - cascading transistors, condensers, operational amplifiers, etc.
It&amp;rsquo;s possible to model them accurately in software, and I did so myself, implementing Maxon&amp;rsquo;s OD808 overdrive pedal in C++ as my diploma project for graduation.
The diploma itself was about precise software modeling of analog systems, and the guitar pedal was a practical example I could show.
You should have seen the faces of the diploma committee when I pulled out a guitar for a project demonstration.
Better, you should have seen MY face, when the head of department took my guitar and started blasting Iron Maiden riffs.&lt;/p&gt;
&lt;p&gt;However, modeling these schematics accurately and working in real-time is hard.
Especially, when we&amp;rsquo;re talking about emulating tubes or tape machines.
People still did, but the results were not as close to the real thing, as one might like, and sound engineers are picky for the details.
But then there was another way of modeling - feed the raw signal through your equipment of choice, be it a tube amp, or some weird pedal schematic, capture the result, and train a neural network so it could reproduce it flawlessly.
This is the technology behind &lt;a href=&#34;https://www.neuralampmodeler.com/&#34; target=&#34;_blank&#34;&gt;Neural Amp Modeler&lt;/a&gt; and other such projects.&lt;/p&gt;
&lt;p&gt;This is where neural network technology shines in my opinion - you get accurate results, even though accurately emulating entire circuits with tubes in real time is still a hard task for programmers.
It sure can be done manually, and there are successful examples, where individual components of the circuit are programmed as separate modules, and then the whole circuit is constructed from them.
That&amp;rsquo;s the approach I took with my diploma project as well, but it still takes much more time than just training a model with a pair of &lt;code&gt;.WAV&lt;/code&gt; files.
And the neural network method comes with another real benefit allowing you to capture your sound exactly as is for later use.
For example, if you&amp;rsquo;re recording at the studio, and you want to patch things later or re-record certain parts, you can capture your studio sound, and then reproduce it later.&lt;/p&gt;
&lt;p&gt;There are other fields, where neural networks can be helpful, I won&amp;rsquo;t go listing all such cases, I&amp;rsquo;m just going into this tangent so that you understand that I&amp;rsquo;m not against neural networks in general.
However.&lt;/p&gt;
&lt;p&gt;When ChatGPT3 was first announced, people started going crazy.
We had no real breakthroughs for quite a few years, GPT2 wasn&amp;rsquo;t really good.
Image and video generation models weren&amp;rsquo;t good either.
Then suddenly, GPT3 talks close to being confused with a real person, and images generated by other models start looking correct, and not like a mush of pixels.
People notice that GPT3 can generate code in most programming languages, and make attempts at problem-solving and such.&lt;/p&gt;
&lt;p&gt;Fast forward a few months, and we have first coding assistants and IDEs with a primary focus on AI for development and refactoring.
The internet is becoming worse by the day - AI-generated articles pollute search results, and you don&amp;rsquo;t know if the thing is real or not when looking at &amp;ldquo;drawings&amp;rdquo;.
AI-generated music pollutes streaming services, often sounding awfully lot like some other artist, without acknowledging that it was trained on their music.
Some streaming services even announced that now you can remix the music with AI if you have a paid plan.
People accuse one another of the use of AI to pretend that they know how to do what they do.
The worst.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-04-22-am-i-becoming-obsolete-or-just-older/youtube_comment.png&#34;
         alt=&#34;Figure 2: A comment to the Generative AI is a Parasitic Cancer video by Freya Holmér&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;A comment to the &lt;a href=&#34;https://www.youtube.com/watch?v=-opBifFfsMY&#34; target=&#34;_blank&#34;&gt;Generative AI is a Parasitic Cancer&lt;/a&gt; video by &lt;a href=&#34;https://www.youtube.com/@acegikmo&#34; target=&#34;_blank&#34;&gt;Freya Holmér&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then, there&amp;rsquo;s the new hot thing - vibe coding.
I&amp;rsquo;m living under a rock, I know that, because I don&amp;rsquo;t follow news, tech hype reaches me mostly via gossip in real life.
So when I first heard the term vibe coding, I naturally assumed that it&amp;rsquo;s another one of these &amp;ldquo;Lofi girl&amp;rdquo;-type work setups where you have a comfy environment for coding with good vibes.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-04-22-am-i-becoming-obsolete-or-just-older/lofi_girl.png&#34;
         alt=&#34;Figure 3: this kind of stuff, just imagine she&amp;amp;rsquo;s programming. I guess, I could generate an image where she&amp;amp;rsquo;s programming for real, but then this post would be hypocrisy.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;this kind of stuff, just imagine she&amp;rsquo;s programming. I guess, I could generate an image where she&amp;rsquo;s programming for real, but then this post would be hypocrisy.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is pretty much what I do when I have free time to work on my personal projects.
I prepare myself a nice cup of coffee with steamed milk and peanut butter&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, sit down at my desk, put on headphones, and enjoy my coding time in the late evening.
Vibes, right?
Nope!
Apparently, vibe coding is when you explain to your AI-based editor what the heck you wanted to do, except you&amp;rsquo;re much more into debugging code written for you.
WTF it is calling &lt;em&gt;vibe coding&lt;/em&gt;?
I wouldn&amp;rsquo;t mind it being called AI coding, but &lt;em&gt;vibe&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;I get it, AI is a hot new thing, and people want to use new shiny things because it triggers a dopamine hit.
But toying with something for fun, or being passionate about things should still remain reasonable.
It&amp;rsquo;s fine when you do this for fun, or sparingly, but when all you do is now done by AI, it starts getting a bit too far in my book.&lt;/p&gt;
&lt;p&gt;I see AI-generated images in presentations and I cringe.&lt;/p&gt;
&lt;p&gt;I see how people brag about how they used AI to do &amp;ldquo;this and that&amp;rdquo;, even though the task at hand was easy and I cringe.&lt;/p&gt;
&lt;p&gt;I see how people misuse AI for harder tasks that can still be done without AI perfectly fine, with a much lower error rate, and I cringe again.&lt;/p&gt;
&lt;p&gt;I see posts about how vibe coding brings back joy to programming, and I only have one question - what joy?
If you did enjoy programming, but felt down recently, I think AI is going to make you feel better in the short term, but burndown will hit you again soon enough when the novelty wears off.
And if you didn&amp;rsquo;t enjoy programming in the first place, how AI is going to help you enjoy it?
Because you don&amp;rsquo;t have to do it manually?&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t enjoy the process, AI won&amp;rsquo;t make it more enjoyable.
You will simply offload the unenjoyable part to AI, and then gaslight yourself.&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;Phew.&lt;/p&gt;
&lt;p&gt;These are the kinds of thoughts I had in my head lately.
And when I&amp;rsquo;m annoyed at something for no apparent reason I usually start reflecting on it in hopes to understand the source of the problem for me.
Worrying over nothing is the worst thing you can do for your mental health.
Like, If I don&amp;rsquo;t use AI, I can choose not to care about others who use AI, and continue to live my life like I did before.
That&amp;rsquo;s what I did before, like when blockchain and NFT were the hot new topics in town.&lt;/p&gt;
&lt;p&gt;However, AI-assisted coding practically hurts me even without me participating in it.
First, I chose to ignore AI assistants, heck I don&amp;rsquo;t even use non-AI assistants such as &lt;abbr title=&#34;Language Server Protocol&#34;&gt;LSP&lt;/abbr&gt; that much.
So when I talk to people, who use AI, I get weird looks, like: &amp;ldquo;Man, you&amp;rsquo;re gonna be obsolete in 5 years if you don&amp;rsquo;t learn how to use AIs, it makes you much more efficient&amp;rdquo;.
Am I?&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think efficiency is in speed only - it doesn&amp;rsquo;t really matter how fast you can produce code.
Programming is mostly thinking a lot, and then writing a little.
It sure does matter to a business, because today&amp;rsquo;s main tactic is &lt;abbr title=&#34;Time To Market&#34;&gt;TTM&lt;/abbr&gt; optimization, but that&amp;rsquo;s another topic.&lt;/p&gt;
&lt;p&gt;I think relying on AIs for coding is going to hurt us in the long run.
Count me old-school, but I believe that today a lot of people in the programming world don&amp;rsquo;t know how to code.
You&amp;rsquo;d be surprised how little people know these days.
Ask them the difference between an array and a vector, and they won&amp;rsquo;t be able to tell the difference.
Don&amp;rsquo;t get me started on advanced topics like asynchronous/parallel programming, or even more basic features like closures.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve seen a lot of people who think that they know what they&amp;rsquo;re doing, but when asked about certain internal characteristics of the language/framework/library they use, that did matter to the problem at hand, they stumbled and couldn&amp;rsquo;t answer.
And I&amp;rsquo;m no better, I was there too - I&amp;rsquo;ve been writing code for bare-metal in C during the first two years at my first-ever job and didn&amp;rsquo;t understand anything.
Only after I delved deeply into the language and SOC stuff, I started understanding what and why.
It improved my results at work and tremendously helped me beyond just C later.
So I believe, that people can learn, but would they if everything is done by AI?&lt;/p&gt;
&lt;p&gt;I can confidently say, that I know Lua deeply enough to understand how its bytecode VM works.
I also can confidently say, that I know how most of Clojure works internally.
But I still can&amp;rsquo;t confidently say that I&amp;rsquo;m a great programmer.
A decent one, maybe, but I still don&amp;rsquo;t know a lot of stuff behind the scenes.
This is why I constantly delve deeper into the technology I&amp;rsquo;m using, trying to understand the inner workings of it.&lt;/p&gt;
&lt;p&gt;And now we have AI assistants, practically writing programs for these people, and they can&amp;rsquo;t reason about the code written by hand, let alone generated code.
I&amp;rsquo;ve seen people applying for a job, and failing miserably on the simplest questions on the coding interview.
They can output the solution for tricky Leetcode tasks, but can&amp;rsquo;t explain them.
Some are even proud that they can make AI assistants solve the problem for them without them even trying to understand the problem.
I, myself, can&amp;rsquo;t solve these Leetcode problems, but I still can write robust code for the real-world task at hand.&lt;/p&gt;
&lt;p&gt;Recently, I encountered a message in a group chat, that pretty much triggered me to write this post, with the following contents:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are orders of magnitude fewer code examples for ClojureDart, which makes it very difficult to train LLMs.
Examples from regular Clojure will probably be pulled up, but the libraries won&amp;rsquo;t work - you&amp;rsquo;ll need to port them first.&lt;/p&gt;
&lt;p&gt;For a &lt;strong&gt;beginner&lt;/strong&gt;, this is &lt;strong&gt;a very large and painful entry threshold&lt;/strong&gt;, especially &lt;strong&gt;if there is no desire to write the code yourself and delve deeply into the language.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Oh, how did people even learn to code before LLMs existed?
I imagine it was so hard and painful!
Imagine - learning the language by writing code and understanding what you&amp;rsquo;re doing, am I right?
This is so wrong on so many levels.&lt;/p&gt;
&lt;p&gt;First of all, if there is no desire to write the code yourself, why the heck do you want to be a programmer?
This code is going to run on a machine, so it should be well understood, otherwise it&amp;rsquo;s a time bomb waiting to explode.
And with LLMs and vibe coding, the whole point is that you don&amp;rsquo;t look into the code that much.
Or at all.&lt;/p&gt;
&lt;p&gt;And, I&amp;rsquo;m not talking about using LLMs - even without them hallucinating a solution today we can&amp;rsquo;t write reliable software that works properly all of the time.
I get frequent crashes when doing mundane tasks - if I were to take a screenshot every time a program hangs or crashes, making me lose my work, my screenshot folder would fill up my hard drive.
Most programs today can&amp;rsquo;t achieve even &lt;a href=&#34;https://en.wikipedia.org/wiki/High_availability#%22Nines%22&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;four nines&amp;rdquo;&lt;/a&gt;, let alone five or six nines of uptime.
Your Windows laptop will suddenly reboot to install updates, so even if your application can theoretically achieve &amp;ldquo;five nines&amp;rdquo;, the platform it is running on can&amp;rsquo;t.
I lost work due to Windows updating the .NET Framework, why the heck does it require a reboot?&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s software is in a miserable state.
We have a lot of over-engineered stuff at the base of our software.
Legacy code creeps in, making writing new code harder.
Bugs are today&amp;rsquo;s norm - I&amp;rsquo;m still amazed that everything is holding up, instead of falling apart.&lt;/p&gt;
&lt;p&gt;If engineers were as bad as programmers today, we would all be &lt;strong&gt;dead&lt;/strong&gt;, lying flattened under collapsed buildings.
Oh, wait&amp;hellip;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;So am I becoming obsolete or just getting older and more grumpy?
I guess it&amp;rsquo;s both.&lt;/p&gt;
&lt;p&gt;I always wondered when would I become one of those old people who don&amp;rsquo;t understand modern technology.
I was born in the 90s, and saw firsthand how technology became more and more advanced - I had access to a computer since the age of three.
My folks don&amp;rsquo;t understand modern social networks that well, let alone all this AI stuff.
Now I&amp;rsquo;ve become a part of the club, I guess - I also don&amp;rsquo;t understand modern social networks and all this AI stuff.
Heck, my dad is probably more advanced in tech than me, as he&amp;rsquo;s been doing this smart-home thing for a while now, and I&amp;rsquo;m not understanding any of it.&lt;/p&gt;
&lt;p&gt;Programming is both a job and a hobby of mine, I like writing code to solve problems I often impose it on myself for the fun of it.
I like to think about solutions, and if I can&amp;rsquo;t do it myself, I search online like in the good old days, learning in the process.&lt;/p&gt;
&lt;p&gt;You can argue, that an AI chatbot is a glorified search interface, except it&amp;rsquo;s not exactly that in my opinion.
Today&amp;rsquo;s AI chatbots don&amp;rsquo;t just present you with existing information, instead, they reconstruct it.
LLMs are more or less a decompression algorithm, except not precise in most cases.
They can hallucinate a solution, and still sound as confident as if it was true.
Keep in mind, that an AI chatbot doesn&amp;rsquo;t &lt;em&gt;understand&lt;/em&gt; what it&amp;rsquo;s outputting, for now at least.
People do that too, unfortunately, but at least they don&amp;rsquo;t sound as confident when they clearly don&amp;rsquo;t know what they talking about (yeah, sure).&lt;/p&gt;
&lt;p&gt;Sometimes, beginner programmers who only know how to code with LLMs face the harsh reality, that LLMs can&amp;rsquo;t solve all problems.
For now.
Maybe in the upcoming years, large language models will become so sophisticated that it would be possible.
I don&amp;rsquo;t know.
And If such a beginner realizes, that they still need to learn things, the internet is already full of articles generated with AIs by people who don&amp;rsquo;t understand the topic, making it much harder for them to learn properly.
I&amp;rsquo;m facing this problem too, each time I want to learn something new, figuring out halfway through the article that it is an AI slop.&lt;/p&gt;
&lt;p&gt;Maybe one day I will have to use AI because my job will demand it, and I will change my opinion on this whole thing.
Or maybe I&amp;rsquo;ll change the job instead, depending on the circumstances.
Blacksmithing looks interesting.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-04-22-am-i-becoming-obsolete-or-just-older/blacksmithing.jpg&#34;
         alt=&#34;Figure 4: A poker I made&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;A poker I made&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Or maybe woodworking?
Or pottery?
Unless AI would do these things too by that time.
Of course not.&lt;/p&gt;
&lt;p&gt;Of course not.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;BTW, amazing recipe: 12 grams of coffee beans, grounded for double shot espresso, about 35-40 grams of salty peanut butter, and steamed milk. Nice texture and taste.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;AI is apparently used in engineering too now.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Am I becoming obsolete or just older?&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 22 Apr 2025 00:36:00 +0300</pubDate>
    </item><item>
      <title>String interpolation in Lua</title>
      <link>https://andreyor.st/posts/2025-04-07-string-interpolation-in-lua/</link>
      <guid>https://andreyor.st/posts/2025-04-07-string-interpolation-in-lua/</guid>
      <description>&lt;p&gt;If you know Python or do a lot of shell scripting (or even write in Perl), you&amp;rsquo;re probably familiar with the ability of these languages to reference variables or even expressions from string literals.&lt;/p&gt;
&lt;p&gt;In a shell, it is possible to do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hello, &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$user&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# prints: Hello, &amp;lt;your username here&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2 + 2 = &lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;$(&lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;echo&lt;/span&gt; 2 + 2 | bc&lt;span style=&#34;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# 2 + 2 = 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A similar feature exists for Python with &lt;a href=&#34;https://docs.python.org/3/tutorial/inputoutput.html#tut-f-strings&#34; target=&#34;_blank&#34;&gt;f-strings&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{&lt;/span&gt;2 + 2 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;= }&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# &amp;#39;2 + 2 = 4&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a cool feature!
I wish I could do this in Lua!&lt;/p&gt;
&lt;p&gt;Unfortunately, Lua doesn&amp;rsquo;t have such a feature, and we&amp;rsquo;re stuck with plain ol&amp;rsquo; &lt;code&gt;string.format()&lt;/code&gt;.
Which is fine, but it has some quirks.&lt;/p&gt;
&lt;p&gt;For instance, when you need to repeat the same thing several times in the resulting string, you have to repeat it the same amount of times in the format string, and in the arguments:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;provoke_thought&lt;/span&gt; (what)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(string.format(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;to %s or not to %s&amp;#34;&lt;/span&gt;, what what))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;provoke_thought(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;be&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- to be or not to be&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;provoke_thought(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bee&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- to bee or not to bee&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With f-strings in Python, it can be done like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;provoke_thought&lt;/span&gt; (what):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;to &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{&lt;/span&gt;what&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; or not to &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{&lt;/span&gt;what&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;provoke_thought(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bee&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# to bee or not to bee&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit nicer, as you don&amp;rsquo;t have to repeat both format specifiers and the variable two times.
Another bit of convenience is when you have a lot of arguments:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(string.format(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this string has %d amount of arguments, which are %d (a %s), %q (a %s), and %p (a pointer)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    n,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    answer,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    type(answer),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    greeting,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    type(greeting),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    string.format))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which prints, assuming these variables are defined somewhere, the following message:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;this string has 4 amount of arguments, which are 42 (a number), &amp;ldquo;hi mom!&amp;rdquo; (a string), and 0x7f0d5fb7f1b0 (a pointer)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, when you have this many variables, it&amp;rsquo;s not as fun to maintain.
Especially, when you need to modify this message, possibly reordering format strings, or removing/adding some.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look how this would look with f-string in Lua:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this string has {n} amount of arguments, which are {answer} (a {type(answer)}), {greeting:%q} (a {type(greeting)}), and {string.format:%p} (a pointer)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- this string has 4 amount of arguments, which are 42 (a number), &amp;#34;hi mom!&amp;#34; (a string), and 0x7f0d5fb7f1b0 (a pointer)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait, didn&amp;rsquo;t I just say, that Lua doesn&amp;rsquo;t have f-strings?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s where I present you &lt;a href=&#34;https://gitlab.com/andreyorst/interpolation.lua&#34; target=&#34;_blank&#34;&gt;interpolation.lua&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;interpolation-dot-lua&#34;&gt;&lt;code&gt;interpolation.lua&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A clever name, I know.&lt;/p&gt;
&lt;p&gt;This is a small library I made, that handles string interpolation in Lua in a similar way to Python&amp;rsquo;s f-strings.
There are some differences, of course, but in general, it should be familiar to you, if you ever used one or another variant of this feature.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at some of its capabilities.&lt;/p&gt;
&lt;p&gt;You require this library like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; f = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;interpolation&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now you have the function &lt;code&gt;f&lt;/code&gt;, which accepts a string, parses it, and spits out the result, formatted accordingly to the expansions in &lt;code&gt;{}&lt;/code&gt;.
When there are no expansions, the string is returned as-is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi, mom&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hi, mom
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, when there are expansions, you can do various things.
For example, you can define some variables, and reference them in the string:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; x, y = 4, 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{x}{y}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;42
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can even evaluate expressions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; x, y = 40, 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;The Answer is: {x + y}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;The Answer is: 42
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One cool feature is the &lt;code&gt;=&lt;/code&gt; modifier, which adds the original expression to the output string:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; x, y = 40, 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{x + y = }&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;x + y = 42
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s like when I&amp;rsquo;m doing literate programming in Org-mode, where I can do a similar thing by writing &lt;code&gt;src_lua[:exports both :post format-result(result=*this*) :wrap]{return 1 + 2}&lt;/code&gt;, and it will expand to &lt;span class=&#34;inline-src language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;code&gt;return 1 + 2&lt;/code&gt;&lt;/span&gt; = &lt;code&gt;3&lt;/code&gt;.
Except, much less verbose.&lt;/p&gt;
&lt;p&gt;As I have shown before, the same format specifiers are available, as per &lt;code&gt;string.format&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; x, y = 40, 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{x + y = :%X}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;x + y = 2A
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s look at how this is implemented because there are some tricks.&lt;/p&gt;
&lt;h2 id=&#34;the-parser&#34;&gt;The parser&lt;/h2&gt;
&lt;p&gt;First things first, this is not a mere string substitution, where I look for something like &lt;code&gt;{([^}]*)}&lt;/code&gt; and replace the entire thing with some value.
Instead, there&amp;rsquo;s a parser, which reads the string byte-by-byte until it encounters the &lt;code&gt;{&lt;/code&gt; character.&lt;/p&gt;
&lt;p&gt;To read a string byte-by-byte I had to port a &lt;code&gt;string-reader&lt;/code&gt; from my &lt;a href=&#34;https://gitlab.com/andreyorst/reader.fnl&#34; target=&#34;_blank&#34;&gt;reader.fnl&lt;/a&gt; project.
After passing a string to the &lt;code&gt;string-reader&lt;/code&gt; function, we get back a reader object with the following methods: &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;lines&lt;/code&gt;, &lt;code&gt;peek&lt;/code&gt;, &lt;code&gt;length&lt;/code&gt;, and &lt;code&gt;close&lt;/code&gt;.
This library doesn&amp;rsquo;t really use anything but &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;peek&lt;/code&gt;, and &lt;code&gt;close&lt;/code&gt;, but it&amp;rsquo;s good to have the rest still.&lt;/p&gt;
&lt;p&gt;Next, the parser itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse_fstring&lt;/span&gt;(str)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; rdr, chars, exprs = string_reader(str), {}, {n=0}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; parse(rdr, chars, exprs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we prepare some storage objects, and the reader, and call the main &lt;code&gt;parse&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;(rdr, chars, exprs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; char = rdr:peek(1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; char == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rdr:read(1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        parse_expansion(rdr, chars, exprs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; parse(rdr, chars, exprs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; char ~= &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        chars[#chars+1] = rdr:read(1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; parse(rdr, chars, exprs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; table.concat(chars), exprs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It looks like a fairly straightforward parser, but the meat and bones are in the &lt;code&gt;parse_expansion&lt;/code&gt; function.
We call it when we encounter a &lt;code&gt;{&lt;/code&gt; in the string.
It&amp;rsquo;s pretty big because it has to handle several cases.&lt;/p&gt;
&lt;p&gt;Once we&amp;rsquo;ve found &lt;code&gt;{&lt;/code&gt; we enter expansion parsing mode.
In this mode, we look for these cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We&amp;rsquo;ve found another &lt;code&gt;{&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;ve found a &lt;code&gt;&amp;quot;&lt;/code&gt; or &lt;code&gt;&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;ve found an equal sign: &lt;code&gt;=&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;ve found a colon followed by percent: &lt;code&gt;:%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Finally, we&amp;rsquo;ve found the closing &lt;code&gt;}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we find another opening curly, that means that the expansion contains a table literal.
In this case, we enter another parsing mode, that parses a table, until it finds the matching amount of closing curly braces.
So any level of table nesting is supported.&lt;/p&gt;
&lt;p&gt;If we find a &lt;code&gt;&amp;quot;&lt;/code&gt; or &lt;code&gt;&#39;&lt;/code&gt;, it means that the expansion is holding a literal string, so we enter a string parsing mode.
This means a few things to us, because inside strings we should not treat both special characters described below, and table delimiters in the table parser as well.
So the table parser also uses the string parser.&lt;/p&gt;
&lt;p&gt;Otherwise, if we&amp;rsquo;re outside of a string or a table, we process the rest of the special characters.&lt;/p&gt;
&lt;p&gt;If we find the &lt;code&gt;=&lt;/code&gt; somewhere before the format sequence, we inject the current expression into the resulting string, and then append a format specifier, &lt;code&gt;%s&lt;/code&gt; by default, unless changed via &lt;code&gt;:%&lt;/code&gt; sequence.&lt;/p&gt;
&lt;p&gt;If we find the &lt;code&gt;:%&lt;/code&gt; in a string, we assume that this starts the format sequence of the expansion.
So we enter another parsing mode, where we parse and remember the format specifier.&lt;/p&gt;
&lt;p&gt;After that, we scan for a closing &lt;code&gt;}&lt;/code&gt;. If there&amp;rsquo;s something else after the format sequence, we signal an error, as there should not be anything but spaces.&lt;/p&gt;
&lt;p&gt;I glossed over this, so if you&amp;rsquo;re interested in more details of how this works, I welcome you to read the &lt;a href=&#34;https://gitlab.com/andreyorst/interpolation.lua/-/blob/8fe5986580473904c87fb9bbabc299123b56fa31/interpolation.lua#L169-302%20&#34; target=&#34;_blank&#34;&gt;code&lt;/a&gt;.
Next, let&amp;rsquo;s see how variables and expressions are turned into values.&lt;/p&gt;
&lt;h2 id=&#34;expansion-substitution&#34;&gt;Expansion substitution&lt;/h2&gt;
&lt;p&gt;At the start of the &lt;code&gt;f&lt;/code&gt; function, we create an environment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;env = setmetatable(locals(), { __index = setmetatable(upvalues(), { __index = _G })})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This environment mimics what the Lua VM can see when it needs to get the value of a variable onto the stack.&lt;/p&gt;
&lt;p&gt;First, we obtain all locals from the current scope, right outside of the function call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; idx, variables = 1, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ln, lv = debug.getlocal(3, idx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ln ~= &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            variables[ln] = lv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idx = 1 + idx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; variables
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a rather simple function, that relies on &lt;code&gt;debug.getlocal&lt;/code&gt; to obtain all visible local variables - their names and values.
So we store it in the table.&lt;/p&gt;
&lt;p&gt;Next are upvalues.
Upvalues are variables in outer scopes, so we need to get them separately:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;upvalues&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; variables, idx, func = {}, 1, debug.getinfo(3, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt;).func
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ln, lv = debug.getupvalue(func, idx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ln ~= &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            variables[ln] = lv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idx = 1 + idx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; variables
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s similar to &lt;code&gt;locals&lt;/code&gt;, except it uses &lt;code&gt;debug.getupvalue&lt;/code&gt;, ans stores variable names and their values into a table.&lt;/p&gt;
&lt;p&gt;We then compose these tables via the &lt;code&gt;__index&lt;/code&gt; metamethod, maintaining the scope hierarchy.
If some variable &lt;code&gt;x&lt;/code&gt; exists as a local but also exists as an upvalue, we will correctly see the local &lt;code&gt;x&lt;/code&gt; value.
Otherwise, if &lt;code&gt;x&lt;/code&gt; is not in the table returned by &lt;code&gt;locals&lt;/code&gt;, we automatically look it in &lt;code&gt;locals&lt;/code&gt;&amp;rsquo; &lt;code&gt;__index&lt;/code&gt; metatable.
And if it&amp;rsquo;s not there, it might be in the &lt;code&gt;_G&lt;/code&gt; table for globals.&lt;/p&gt;
&lt;h3 id=&#34;expressionn-evaluation&#34;&gt;Expressionn evaluation&lt;/h3&gt;
&lt;p&gt;However, not all things can be looked up the way described above.
For example &lt;code&gt;f&amp;quot;{math.pi}&amp;quot;&lt;/code&gt; would fail, despite &lt;code&gt;math&lt;/code&gt; being in &lt;code&gt;_G&lt;/code&gt;, because we would look for &lt;code&gt;_G[&amp;quot;math.pi&amp;quot;]&lt;/code&gt;, and there&amp;rsquo;s no such thing there.
And we can&amp;rsquo;t really assume that any sequence of characters with &lt;code&gt;.&lt;/code&gt; in the middle is a table lookup, so we can&amp;rsquo;t translate &lt;code&gt;{math.pi}&lt;/code&gt; to &lt;code&gt;_G[&amp;quot;math&amp;quot;][&amp;quot;pi&amp;quot;]&lt;/code&gt;.
Even if we could, it wouldn&amp;rsquo;t be a good solution, because we can also have expressions like &lt;code&gt;f&amp;quot;{1 + 2}&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of implementing a small interpreted language for the expansions, I decided to use Lua&amp;rsquo;s &lt;code&gt;load&lt;/code&gt; function (and &lt;code&gt;loadstring&lt;/code&gt; for Lua 5.1):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt;(code, env)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; env = env &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; rawget(_G, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;_ENV&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; _G
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; setfenv, loadstring, f = rawget(_G, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;setfenv&amp;#34;&lt;/span&gt;), rawget(_G, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loadstring&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= setfenv) &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= loadstring) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        f = assert(loadstring(code))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        setfenv(f, env)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; assert(&lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= load, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;neither load nor loadstring are available&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        f = assert(load(code, &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;t&amp;#34;&lt;/span&gt;, env))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So our lookup mechanism is as follows.&lt;/p&gt;
&lt;p&gt;So our lookup mechanism is as follows.&lt;/p&gt;
&lt;p&gt;First, we try to look at the variable name directly in the &lt;code&gt;env&lt;/code&gt; table.
Then, if nothing was found, we try to &lt;code&gt;eval&lt;/code&gt; an expression.
However, you can&amp;rsquo;t simply do &lt;code&gt;eval(&amp;quot;1 + 2&amp;quot;)&lt;/code&gt; in Lua, because Lua requires explicit &lt;code&gt;return&lt;/code&gt; even on the top level.
So our code looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; value = env[name] &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; eval(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;return &amp;#34;&lt;/span&gt; .. name, env)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;bypassing-variable-lookup&#34;&gt;Bypassing variable lookup&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s one quirk about this implementation, that I&amp;rsquo;m not sure how to fix.
I noticed it randomly when I was writing tests.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s the output of this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string_adder&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{x + y = }&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; g = string_adder(40)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;g(2)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If your guess is a string &lt;code&gt;&amp;quot;40 + 2 = 42&amp;quot;&lt;/code&gt;, then your understanding of this library is correct, but your understanding of the underlying Lua runtime is a bit incomplete.
It&amp;rsquo;s not at all a problem, this stuff is not required to use Lua, and the problem is subtle.&lt;/p&gt;
&lt;p&gt;The resulting string won&amp;rsquo;t even be returned, because it will raise an error &lt;code&gt;attempt to perform arithmetic on a nil value&lt;/code&gt;.
Why is that?&lt;/p&gt;
&lt;p&gt;Before I explain, let&amp;rsquo;s fix this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string_adder&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{x + y = }&amp;#34;&lt;/span&gt;, x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; g = string_adder(40)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(g(2))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the result is indeed &lt;code&gt;&amp;quot;40 + 2 = 42&amp;quot;&lt;/code&gt;, so what gives?&lt;/p&gt;
&lt;p&gt;Apparently, if the code never actually references the variable, it won&amp;rsquo;t be visible by &lt;code&gt;debug.getupvalue&lt;/code&gt;.
By code, I mean the string of the actual code that is being compiled by the Lua VM into bytecode.
It&amp;rsquo;s logically sound, though - why would the compiler even bother about storing an upvalue if it is never used?
And the compiler doesn&amp;rsquo;t know that we will in fact use this upvalue in our &lt;code&gt;eval&lt;/code&gt; function, by extracting it from the string in this special way.&lt;/p&gt;
&lt;p&gt;So if this fails, and all you need is to return a formatted string, what do you do?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;f&lt;/code&gt; function got you covered - you don&amp;rsquo;t need to rely on local lookup, instead, you can provide your own &lt;code&gt;env&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string_adder&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{x + y = }&amp;#34;&lt;/span&gt;, {x = x, y = y})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; g = string_adder(40)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;g(2)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks like &lt;code&gt;string.format&lt;/code&gt;, again, except it allows providing variables in any order and without duplicates.
I mean, &lt;code&gt;f(&amp;quot;Agent {x}{x}{y}&amp;quot;, {x = 0, y = 6-1})&lt;/code&gt; is still a bit more concise in my book than repeating &lt;code&gt;x&lt;/code&gt; several times.&lt;/p&gt;
&lt;p&gt;Passing your own &lt;code&gt;env&lt;/code&gt; prevents any other kind of lookup, so no more globals, upvalues, or locals will be found.
This also makes this library usable without the &lt;code&gt;debug&lt;/code&gt; library, although it still requires &lt;code&gt;load&lt;/code&gt; for evaluation.
Again, I don&amp;rsquo;t want to write a Lua interpreter as a fallback for that.&lt;/p&gt;
&lt;h2 id=&#34;a-cool-feature&#34;&gt;A cool feature?&lt;/h2&gt;
&lt;p&gt;For me, sure yes.
I like this to be in the language I work with, as it makes some specific cases less of a burden to write and maintain.
Of course, not all strings should become f-strings, there&amp;rsquo;s still a place both for &lt;code&gt;string.format&lt;/code&gt; and plain string concatenation.&lt;/p&gt;
&lt;p&gt;Now, why do I make this library for Lua in Lua, and not for Fennel, as I mainly do my hobby project in it?
First of all, I enjoy occasionally writing in pure Lua.
I like the language, it has its charm.
Fennel is objectively a better dialect of Lua, but sometimes I want to be reminded why it is.&lt;/p&gt;
&lt;p&gt;Second, Lua allows for calling functions on strings without parentheses: &lt;code&gt;print &amp;quot;foo&amp;quot;&lt;/code&gt;.
This feature also applies to tables, meaning you can create small DSLs in your program.
For example, one of my libraries implements a JSON encoder.
In Lua, I can call &lt;code&gt;json{x = 1, y = 2}&lt;/code&gt; and get back a string &lt;code&gt;&#39;{&amp;quot;x&amp;quot;: 1, &amp;quot;y&amp;quot;: 2}&#39;&lt;/code&gt;.
This way I don&amp;rsquo;t need to write JSON in strings manually, and I can reuse Lua&amp;rsquo;s table syntax and my editor&amp;rsquo;s formatting features.&lt;/p&gt;
&lt;p&gt;This might be a silly reason to make this in Lua, but I wanted to make this library because it sounded fun and easy.
In the end, it wasn&amp;rsquo;t easy but was still pretty fun.
It might be a better fit for Fennel still because all these &lt;code&gt;f-strings&lt;/code&gt; could be generated at compile time, additionally solving the upvalue problem, because variables will be referenced, and there would be no need for a custom evaluation step.&lt;/p&gt;
&lt;p&gt;This is why I think this feature should be a part of the language and implemented in the compiler itself.
I have a toy language that implements a bytecode VM, so perhaps I could try to make it there to see if it would work well.
But I hope to see f-strings in Lua someday.
Maybe in Lua 12.4, who knows?&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: String interpolation in Lua&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 07 Apr 2025 19:03:00 +0300</pubDate>
    </item><item>
      <title>Dynamic font-lock for Fennel</title>
      <link>https://andreyor.st/posts/2025-03-10-dynamic-font-lock-for-fennel/</link>
      <guid>https://andreyor.st/posts/2025-03-10-dynamic-font-lock-for-fennel/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been working on adding a dynamic font-locking for &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode&#34; target=&#34;_blank&#34;&gt;fennel-mode&lt;/a&gt; for a while now.
The first attempt started years ago, in July 2022, and were quite crude.
It consisted of sending a special code to the REPL that would return me a list of macro names, and then I created a regular expression that matched all these names for syntax highlighting.
This had several problems.&lt;/p&gt;
&lt;p&gt;First, this meant that any macro known to the REPL would be highlighted.
This is not great, as macros in Fennel can be loaded from any file that you require, but it doesn&amp;rsquo;t mean that they&amp;rsquo;re available to your file in particular.&lt;/p&gt;
&lt;p&gt;For example, imagine you have this code:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/bad-hl.png&#34;
         alt=&#34;Figure 1: All code in this post will be provided as images to better show code highlighting&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;All code in this post will be provided as images to better show code highlighting&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, this code requires the module &lt;code&gt;:foo&lt;/code&gt;, defines a few functions, and finally calls them.
Ignore the fact that the module &lt;code&gt;foo&lt;/code&gt; is unused for now - turn your attention to the colors instead.&lt;/p&gt;
&lt;p&gt;As you can see, &lt;code&gt;fennel-mode&lt;/code&gt; uses colors to tell the user a few things.
Special forms and macros are highlighted in a blueish color.
Inbuilt functions are highlighted in purple.
Names of declared functions are also in purple, but not their calls.&lt;/p&gt;
&lt;p&gt;However, you can see that for some reason, &lt;code&gt;bar&lt;/code&gt; is highlighted blue, as if it was a special or a macro.
This is because I&amp;rsquo;m using my old implementation of dynamic highlighting.
If we look into the &lt;code&gt;foo&lt;/code&gt; module, we&amp;rsquo;ll see that it requires a macro module, that defines &lt;code&gt;bar&lt;/code&gt; as a macro.
It&amp;rsquo;s not a problem - macros in Fennel are only available in the module they&amp;rsquo;re required, so there&amp;rsquo;s no name conflict here, as you would expect.
However, highlighting is not very smart.&lt;/p&gt;
&lt;p&gt;When syntax highlighting is applied, a request is sent to the REPL to get all available macros.
Then no distinction is made for where these macros are coming from, hence the wrong highlighting.&lt;/p&gt;
&lt;p&gt;Another tricky case, that I don&amp;rsquo;t see implemented around is scoping:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/bad-scoping.png&#34;
         alt=&#34;Figure 2: Like, imagine, otherwise I&amp;amp;rsquo;d have to do this highlighting in CSS manually&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Like, imagine, otherwise I&amp;rsquo;d have to do this highlighting in CSS manually&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In Fennel, the &lt;code&gt;macro&lt;/code&gt; special, which is used to define macros, obeys the scoping rules.
Thus when we create a macro inside of the &lt;code&gt;do&lt;/code&gt;&amp;rsquo;s scope, this macro should not be highlighted outside of it.
But again, because the initial implementation of dynamic highlighting didn&amp;rsquo;t care about anything but macro names, the macro was incorrectly highlighted in this case as well.&lt;/p&gt;
&lt;p&gt;Because of these problems, Phil and I decided that this won&amp;rsquo;t be a good feature to bring into &lt;code&gt;fennel-mode&lt;/code&gt; in this state.
The branch rested for almost three years, up until recently, when I started working on &lt;code&gt;fennel-mode&lt;/code&gt; again.&lt;/p&gt;
&lt;p&gt;Recently, I added support for Flymake via the &lt;a href=&#34;https://git.sr.ht/~xerool/fennel-ls/&#34; target=&#34;_blank&#34;&gt;fennel-ls&lt;/a&gt; language server.
That was another old branch of mine, where I added linting via Fennel&amp;rsquo;s own linter plugin, but Phil mentioned that the plugin was never supposed to be used like this.
It was also suggested that since &lt;code&gt;fennel-ls&lt;/code&gt; already existed back then, and it was working with &lt;code&gt;eglot&lt;/code&gt; there was no real need for using Flymake with Fennel&amp;rsquo;s linter plugin.&lt;/p&gt;
&lt;p&gt;I gave this branch a rest, and after a while, when I started using &lt;code&gt;fennel-ls&lt;/code&gt; myself, I decided to contribute a small change so that it could be used from Flymake.
Personally, I don&amp;rsquo;t need a full-blown language server for Fennel, because everything I need is provided by the Fennel Proto REPL, but I do want some linting capabilities.
So after merging the Flymake branch into the main &lt;code&gt;fennel-mode&lt;/code&gt; branch, I noticed this old &lt;code&gt;dynamic-font-lock&lt;/code&gt; branch, and decided that &amp;ldquo;it&amp;rsquo;s time to do this&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Thus, I&amp;rsquo;m happy to announce, that all the problems listed above were fixed!
Take a look at this:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/highlighting-not-yet-applied.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Of course, when we just load the file, nothing is highlighted yet, as the syntax highlighting is dynamic.
However, when we load the module into the REPL, the highlighting is applied correctly:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/good-hl.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Once the module is loaded, highlighting is cached, and no further requests to the REPL are sent.
This doesn&amp;rsquo;t, however, mean that when we change the code, the highlighting won&amp;rsquo;t react:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted style=&#34;border-radius: 16px&#34; class=&#34;invertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/dynamic.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I wanted to make this feature for quite some time.
I&amp;rsquo;m a big fan of &lt;a href=&#34;https://cider.mx/&#34; target=&#34;_blank&#34;&gt;CIDER&lt;/a&gt;&amp;rsquo;s dynamic font-locking and have been using it for some years.
It never occurred to me, however, that CIDER doesn&amp;rsquo;t do scoping:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/cider1.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;But Clojure macros are not scoped, like in Fennel, so that&amp;rsquo;s probably fine.
What&amp;rsquo;s not as fine is that it will highlight the macro before it was declared:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2025-03-10-dynamic-font-lock-for-fennel/cider2.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Which would be an error if we were to try to reload this file.
But, for what it&amp;rsquo;s worth, I think CIDER&amp;rsquo;s solution is fine, because again - no special scoping rules, and unless the file loads without errors, no dynamic syntax highlighting would be applied.
For Fennel, however, I wanted a more robust solution.&lt;/p&gt;
&lt;p&gt;For now, this is still available in a &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode/tree/dynamic-font-lock&#34; target=&#34;_blank&#34;&gt;feature branch&lt;/a&gt;, but I&amp;rsquo;m positive that I&amp;rsquo;ll merge this soon, after I give it a bit more testing, and gather some feedback from the users.
If you&amp;rsquo;re a &lt;code&gt;fennel-mode&lt;/code&gt; user, and you use my &lt;code&gt;fennel-proto-repl&lt;/code&gt; module, I encourage you to try out dynamic font-locking and see if it works for you!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Dynamic font-lock for Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 10 Mar 2025 01:26:00 +0300</pubDate>
    </item><item>
      <title>Blog - fifth anniversary</title>
      <link>https://andreyor.st/posts/2025-02-16-blog-fifth-anniversary/</link>
      <guid>https://andreyor.st/posts/2025-02-16-blog-fifth-anniversary/</guid>
      <description>&lt;p&gt;Somehow I&amp;rsquo;ve missed the fifth anniversary of my blog!
Oh well.
Well, it&amp;rsquo;s not that big of a deal, but I want to reflect on my blogging a bit.&lt;/p&gt;
&lt;p&gt;I started this blog on January 27th, 2020 with the following line:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the first public post that I wrote because I&amp;rsquo;ve finally thought that I&amp;rsquo;m clever enough to do so.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&amp;rsquo;s one of the most important decisions I made in the last five years.&lt;/p&gt;
&lt;p&gt;In fact, I wasn&amp;rsquo;t smart enough to make that post.
As I&amp;rsquo;m looking at my first set of articles about GRScheme, it is obvious that these were baby steps.
But this kick-started my interest in writing and more importantly - learning.&lt;/p&gt;
&lt;p&gt;Every time I write a post on this blog is usually because I learned something new.
And every time I learn something new I want to make a post on my blog.
And more often than not I want to learn something new to later make a post about it.&lt;/p&gt;
&lt;p&gt;The only thing I regret is not starting this blog sooner in my life - I&amp;rsquo;m positive that it would help me grow much quicker and I wouldn&amp;rsquo;t make a lot of mistakes that I did.&lt;/p&gt;
&lt;h2 id=&#34;2020&#34;&gt;2020&lt;/h2&gt;
&lt;p&gt;In 2020 most of my posts were all over the place.
I was still figuring out what I wanted to write about and because I only had one recent project I was working on, I decided to use it as a starting point.
That project was &lt;a href=&#34;https://andreyor.st/posts/2020-02-25-grscheme-design-part-1/&#34;&gt;GRScheme&lt;/a&gt; - an implementation of an interpreter of a Scheme-like language written in Rust.&lt;/p&gt;
&lt;p&gt;I was learning Rust because I felt that I couldn&amp;rsquo;t do C for a living and enjoy it at the same time.
Don&amp;rsquo;t get me wrong, I like C, it has its charm, but I was working for almost five years with it at my day job, and it started to wear out.
I didn&amp;rsquo;t want to switch to C++ full-time, so I started looking at alternatives.
Rust was an obvious one - a hot new language with a lot of projects circulating over the web, the whole &amp;ldquo;rewrite it in Rust&amp;rdquo; shtick, etc.&lt;/p&gt;
&lt;p&gt;Rust hit me at a weird time - I was discovering Lisps, and because I liked what I saw in both languages at the time, I decided that writing a Lisp from scratch in Rust would be a fun project.
And a fun project it was!
The result is horrible too!&lt;/p&gt;
&lt;p&gt;I was also messing with Emacs a lot at the time, and Emacs was another reason for my passion for blogging.
You see, I started this blog with Org Mode and Hugo, and I still use them for this blog.
I would probably do so even after Hugo fades away and will be replaced with a new hot thing.
Maybe it already was - I never checked.
Hugo + Org Mode has everything I ever needed.&lt;/p&gt;
&lt;p&gt;Emacs also played a role in my career, because it is configured in Lisp.
And Lisps were an interest of mine at the time so all three things came in nicely.
I configured Emacs with Lisp to use Rust, wrote Lisp in Rust, and blogged about it from Emacs.&lt;/p&gt;
&lt;p&gt;After finishing the project and failing a few interviews for a junior Rust developer position I thought to myself: if I like Lisp that much, maybe I should learn a proper Lisp, instead of toying with a weird implementation of a thing I know nothing of?
Yes, I knew nothing about lisps and still managed to make an interpreter.
A horrible, yet working one, with a lot of bugs, of course.
So I set myself on a journey to find the Lisp I want to learn.&lt;/p&gt;
&lt;p&gt;After examining alternatives, and briefly considering Racket, I stumped on the talk by this guy Rich Hickey about simplicity.
And kinda fell down the rabbit hole with this Clojure language that I never heard of before.&lt;/p&gt;
&lt;p&gt;So after blogging a bit about Rust and &lt;a href=&#34;https://andreyor.st/posts/2020-04-29-text-editors/&#34;&gt;Emacs&lt;/a&gt;, Clojure was the next thing I wanted to learn.
And what better way to learn something than to blog about it?&lt;/p&gt;
&lt;p&gt;I made a &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/&#34;&gt;simple ray casting demo in ClojureScript&lt;/a&gt;, and was pretty confident in my knowledge of the language after just two months of messing with it.
Sure, learning some Scheme beforehand helped, but only to make me feel easier about all these parentheses.
Which I blogged about &lt;a href=&#34;https://andreyor.st/posts/2020-12-03-we-need-to-talk-about-parentheses/&#34;&gt;later&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I applied for the junior Clojure developer into an organization I never heard of before.
This company specializes in information security, and they were looking for a middle-to-senior Clojure developer.
I still don&amp;rsquo;t know how I got this job, but I&amp;rsquo;m extremely glad that I did.&lt;/p&gt;
&lt;p&gt;I feel that I need to address this thing though.
I was applying for a junior developer despite having five years of experience in software development.
Why?&lt;/p&gt;
&lt;p&gt;Simply put - the stack is so different that I might as well don&amp;rsquo;t know anything.
At my previous job, I hadn&amp;rsquo;t written any servers, never talked to a database, and so on.
So junior position was the only thing I could really go for.
Another five years passed since then, and I&amp;rsquo;m no longer a junior developer, but if I ever have to drastically change the stack again I don&amp;rsquo;t mind applying to the junior position again at all.
I learn fast, so I won&amp;rsquo;t be a junior for long.&lt;/p&gt;
&lt;p&gt;2020 was a year I learned about Fennel - another lisp language.
And I &lt;a href=&#34;https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/&#34;&gt;fell in &lt;em&gt;löve&lt;/em&gt;&lt;/a&gt;.
You can kinda see that, given how many there are posts &lt;a href=&#34;https://andreyor.st/tags/fennel/&#34; target=&#34;_blank&#34;&gt;tagged &lt;code&gt;fennel&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;2021&#34;&gt;2021&lt;/h2&gt;
&lt;p&gt;This year was mostly Fennel-focused.
I became a Fennel contributor by &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;re-implementing the pretty-printer&lt;/a&gt;.
This code is still used today, either because it is terribly complex and nobody is brave enough to rewrite it again, or because it works well enough.
I&amp;rsquo;m on the latter side, although I feel that the former one is not entirely incorrect.&lt;/p&gt;
&lt;p&gt;I further experimented with Fennel.
Macros were a hot thing to learn, so I made a &lt;a href=&#34;https://andreyor.st/posts/2021-08-08-condition-system-for-fennel-language-and-lua-runtime/&#34;&gt;condition system&lt;/a&gt; implementation.
This was another attempt at making something I know very little of, by just observing how it behaves.
Turned out pretty well, and completely useless too!&lt;/p&gt;
&lt;p&gt;On the brighter side, I made another library that year that implemented &lt;a href=&#34;https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/&#34;&gt;lazy sequences&lt;/a&gt;.
It was fun to make, and I learned a lot about how lazy sequences work in Clojure along the way.&lt;/p&gt;
&lt;p&gt;The next thing I tried was asynchronous programming.
You see, at work, I started working with asynchronous code, and literally nobody understands asynchronous code.
So the only way to understand async is to write a library for it - I thought to myself.
And so I did.&lt;/p&gt;
&lt;p&gt;This library was horrible, but I didn&amp;rsquo;t realize it until I understood how async works.
Which was way after I made this library.&lt;/p&gt;
&lt;p&gt;This year also was a year when I decided to participate in the Advent of Code event.
I made a post each day, and by day 25 I was so exhausted that I decided that I would never do it again, and hidden all of the posts.
They are still there if you know how to look, but I won&amp;rsquo;t give you any links.&lt;/p&gt;
&lt;p&gt;Also, I grew to hate these AoC posts in the feed.
Being bombarded each December in the RSS feed by &amp;ldquo;Advent of Code - day N shenanigans&amp;rdquo; type of posts kinda ruined AoC for me.&lt;/p&gt;
&lt;h2 id=&#34;2022&#34;&gt;2022&lt;/h2&gt;
&lt;p&gt;2022 wasn&amp;rsquo;t as productive when it came to my personal projects, so I shifted my focus to writing posts in the &amp;ldquo;misc&amp;rdquo; and &amp;ldquo;random-thoughts&amp;rdquo; categories.&lt;/p&gt;
&lt;p&gt;I also &lt;a href=&#34;https://andreyor.st/posts/2022-02-22-new-look/&#34;&gt;changed the theme&lt;/a&gt; of this blog to the current one, and used it ever since.
It is a custom-made theme, and I purposely don&amp;rsquo;t share it.
Don&amp;rsquo;t ask.&lt;/p&gt;
&lt;p&gt;Because this year was more about thinking, rather than making, it might feel less productive, but I made a lot more posts than in the previous year.&lt;/p&gt;
&lt;p&gt;One of my favorite posts from this year is about &lt;a href=&#34;https://andreyor.st/posts/2022-03-29-100-is-the-only-acceptable-test-coverage/&#34;&gt;code coverage&lt;/a&gt;.
I still think that 100% is the only acceptable coverage if you know why you measure coverage at all.&lt;/p&gt;
&lt;p&gt;More Fennel stuff this year though.
I&amp;rsquo;ve participated in my first ever &lt;a href=&#34;https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/&#34;&gt;game jam&lt;/a&gt;, and made a decently-looking game (at least I think so).
I also made a library for evaluating Fennel from Org Mode source code blocks, and turned it into a &lt;a href=&#34;https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/&#34;&gt;kind of a notebook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, I made a &lt;a href=&#34;https://andreyor.st/posts/2022-12-09-fixed-version-of-pipeline-async-and-unordered-pipeline-variants/&#34;&gt;small library&lt;/a&gt; for Clojure, that fixes a &lt;a href=&#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/&#34;&gt;long-standing bug in the &lt;code&gt;core.async&lt;/code&gt; library&lt;/a&gt;.
Sadly, this patch wasn&amp;rsquo;t accepted by Clojure maintainers, but I was expecting that.&lt;/p&gt;
&lt;p&gt;Overall, not a bad year.
I only had three major projects, but I kinda wanted to go for quality over quantity.&lt;/p&gt;
&lt;h2 id=&#34;2023&#34;&gt;2023&lt;/h2&gt;
&lt;p&gt;And I went back to quantity over quality pretty quickly.&lt;/p&gt;
&lt;p&gt;For some reason in 2023, I felt a huge urge to write.
Forty-four posts, including the hidden ones!&lt;/p&gt;
&lt;p&gt;Another bad &lt;a href=&#34;https://andreyor.st/posts/2023-02-01-ad-hoc-async-in-emacs-lisp-via-generators/&#34;&gt;async implementation, now in Emacs Lisp&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A new &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/&#34;&gt;REPL implementation for Fennel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Clojure&amp;rsquo;s &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;&lt;code&gt;core.async&lt;/code&gt; port&lt;/a&gt; to Fennel!
(Finally, a decent one.  All it took was to actually look inside one of the libraries actually used in the industry.)&lt;/p&gt;
&lt;p&gt;And of course, gamedev.&lt;/p&gt;
&lt;p&gt;This year I decided to really get into game development, so I set myself a goal - make five games, each in one month.&lt;/p&gt;
&lt;p&gt;The first game was a &lt;a href=&#34;https://andreyor.st/posts/2023-07-30-game1-results/&#34;&gt;basic platformer&lt;/a&gt;.
I was pumped up and worked on this project a lot.
Probably, the longest I ever worked on a game before or to this day.
After finishing it (stopping would be a more accurate word), I realized how hard it is to pump games out each month.&lt;/p&gt;
&lt;p&gt;The second game didn&amp;rsquo;t go as &lt;a href=&#34;https://andreyor.st/posts/2023-08-25-game2-w44/&#34;&gt;planned&lt;/a&gt; at all.
I was so burned out from the previous game, that I couldn&amp;rsquo;t bring myself to work on the second one.
So the only obvious solution was to start working on the third one, right?&lt;/p&gt;
&lt;p&gt;The third game I actually &lt;a href=&#34;https://andreyor.st/posts/2023-10-01-game3-results/&#34;&gt;managed to complete&lt;/a&gt; to the point of having some kind of a game loop.
Not a good one, but give me some slack - I have been programming non-stop day and night for three full months now.&lt;/p&gt;
&lt;p&gt;The fatigue was real though.
I decided to &lt;a href=&#34;https://andreyor.st/posts/2023-10-19-game4-and-autumn-lisp-game-jam/&#34;&gt;abandon&lt;/a&gt; this self-assigned challenge, after making a portion of a game and deleting everything in frustration.
I&amp;rsquo;ve later written a &lt;a href=&#34;https://andreyor.st/posts/2023-10-29-gamedev-marathon/&#34;&gt;postmortem&lt;/a&gt; on all this marathon thing, and to this day I&amp;rsquo;m recovering and it&amp;rsquo;s really hard for me to get back into game development.
Maybe this year, who knows?&lt;/p&gt;
&lt;p&gt;Apart from gamedev, I decided to revisit the language development field.
So I started working on language by following the &lt;a href=&#34;https://andreyor.st/posts/2023-12-03-thoughts-on-crafting-interpreters-part-1/&#34;&gt;Crafting Interpreters book&lt;/a&gt;.
This was the project I spent most of my time remaining in 2023.&lt;/p&gt;
&lt;h2 id=&#34;2024&#34;&gt;2024&lt;/h2&gt;
&lt;p&gt;The year started with me and my wife getting divorced.
I&amp;rsquo;ve finished the &lt;a href=&#34;https://andreyor.st/posts/2024-01-25-thoughts-on-crafting-interpreters-part-3/&#34;&gt;Crafting Interpreters book&lt;/a&gt;, but this was the last push - I haven&amp;rsquo;t any energy left to continue with the blog.
I made a post reflecting on this blog but later hidden it away.
I wasn&amp;rsquo;t planning on feeling down for long, just needed a break from things.
It&amp;rsquo;s still there to remind me of my past self.&lt;/p&gt;
&lt;p&gt;So I took a break for a full month until I felt the urge to write again.
It started slow, mostly with posts about thinking on various programming topics.
And &lt;a href=&#34;https://andreyor.st/posts/2024-04-02-hobbies/&#34;&gt;hobbies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And I rediscovered my passion for a different hobby I had years ago - playing guitar and recording videos about it!&lt;/p&gt;
&lt;p&gt;&lt;video controls loop&gt;&lt;source src=&#34;https://andreyor.st/2024-12-29-2024-recap/martian-winter.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  Intro cover of A Martian Winter by Angel Vivaldi (Warning - it&#39;s a bit loud)
&lt;/div&gt;
&lt;p&gt;Then an inspiration struck again and I started working like a crazy man on a new &lt;a href=&#34;https://andreyor.st/posts/2024-08-01-fnl-http-improvements/&#34;&gt;passionate project&lt;/a&gt;.
I started working on an asynchronous HTTP client for Fennel, actually applying all of my knowledge and previous projects that I made.
I worked on it almost til the &lt;a href=&#34;https://andreyor.st/posts/2024-11-04-extending-json-encoder-with-custom-types/&#34;&gt;end of the year&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I dipped my toes into &lt;a href=&#34;https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/&#34;&gt;game development&lt;/a&gt; for a brief moment again.&lt;/p&gt;
&lt;p&gt;One of the things I reflected upon was &lt;a href=&#34;https://andreyor.st/posts/2024-12-10-doing-things-blindly/&#34;&gt;doing things blindly&lt;/a&gt;.
That was the style of learning I applied til the last year.
This year was different, I was reading specs, different implementations, and learning from stuff people made instead of reinventing the wheel.
Hopefully, this method will stay with me and evolve further.&lt;/p&gt;
&lt;p&gt;Another spontaneous project was about bringing Fennel into Emacs as a &lt;a href=&#34;https://andreyor.st/posts/2024-12-20-extending-emacs-with-fennel/&#34;&gt;second extension language&lt;/a&gt;.
While working on it, and preparing for the FennelConf 2024 where I wanted to talk about &lt;code&gt;fnl-http&lt;/code&gt; I suddenly found myself working on yet another project that I already made several attempts at - the dependency manager.
So, somehow by the end of the year, I was working on three projects at once again.&lt;/p&gt;
&lt;h2 id=&#34;2025-and-beyond&#34;&gt;2025 and beyond&lt;/h2&gt;
&lt;p&gt;And that&amp;rsquo;s what brings us to 2025!
I&amp;rsquo;m still working on this &lt;a href=&#34;https://andreyor.st/posts/2025-02-16-depsfnl-022-released/&#34;&gt;dependency manager project&lt;/a&gt;, and I have high hopes that it will be useful to the Fennel community.
Not sure what other projects this year will bring, but I hope they will produce exciting and interesting posts!&lt;/p&gt;
&lt;p&gt;All in all, starting this blog five years ago made me who I am today.
My only advice to you - if you want to start doing something, but you&amp;rsquo;re waiting til you&amp;rsquo;re ready, then do not wait!
Act, and you will see that you&amp;rsquo;re probably already capable of doing what you always wanted to do.
And even if you&amp;rsquo;re not, you will clearly see what parts you have to work on.
And others will help you with that.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been here for the past five years, I gladly appreciate that a lot.
A lot of comments were sent to me in 2024, helping me make this blog better, and move through life.
And if you&amp;rsquo;re just passing by, I&amp;rsquo;m still glad that you made it here!&lt;/p&gt;
&lt;p&gt;Thank you for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Blog - fifth anniversary&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 16 Feb 2025 08:52:00 +0300</pubDate>
    </item><item>
      <title>deps.fnl 0.2.2 released</title>
      <link>https://andreyor.st/posts/2025-02-16-depsfnl-022-released/</link>
      <guid>https://andreyor.st/posts/2025-02-16-depsfnl-022-released/</guid>
      <description>&lt;p&gt;I just released a new version of the &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;deps.fnl&lt;/a&gt; project!&lt;/p&gt;
&lt;p&gt;After getting some feedback on the 0.1.0 version and addressing most of it, I&amp;rsquo;m ready to present a new version with improved dependency and conflict handling.&lt;/p&gt;
&lt;h2 id=&#34;major-changes&#34;&gt;Major changes&lt;/h2&gt;
&lt;h3 id=&#34;the-deps-dot-fnl-file-format&#34;&gt;The &lt;code&gt;deps.fnl&lt;/code&gt; file format&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;:deps&lt;/code&gt; field was changed back to use maps, as it was during the prototyping stage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/json.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eebcb40750d6f41ed03fed04373f944dcf297383&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.0-1&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?/init.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before this change the &lt;code&gt;deps.fnl&lt;/code&gt; file would have looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/json.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eebcb40750d6f41ed03fed04373f944dcf297383&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.0-1&amp;#34;&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?/init.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main reason for a change to the use of vectors was the fact that all of the Luarocks dependencies were using the same tree.
Because conflict resolution was made during dependency installation, and maps are unordered, and if any of the libraries had a Luarocks library as its transient dependency, Luarocks would silently override the dependency.
This made conflict checking nondeterministic, and thus error-prone.&lt;/p&gt;
&lt;p&gt;This is no longer an issue, and thus the format can be changed back to maps.&lt;/p&gt;
&lt;h3 id=&#34;conflict-resolution&#34;&gt;Conflict resolution&lt;/h3&gt;
&lt;p&gt;Previously, &lt;code&gt;deps&lt;/code&gt; would use a deterministic order of dependencies and the &lt;code&gt;--allow-conflicts&lt;/code&gt; flag to resolve conflicts.
This meant, that if your project had two dependencies, that had the same transient dependency but of a different version, &lt;code&gt;--allow-conflicts&lt;/code&gt; would honor dependencies that appeared earlier in the order.
For example, if you had dependencies &lt;code&gt;A&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt;, both of which depended on &lt;code&gt;C&lt;/code&gt; of versions &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; project deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; A deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; B deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;deps&lt;/code&gt; script would throw an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[A:1]-&amp;gt;[C:1] conflicts with [B:1]-&amp;gt;[C:2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Previously, this could be resolved by using the &lt;code&gt;--allow-conflicts&lt;/code&gt; flag, meaning that &lt;code&gt;deps&lt;/code&gt; would see the conflict, but ignore it, and use the &lt;code&gt;C&lt;/code&gt; library from the first one encountered in the &lt;code&gt;deps.fnl&lt;/code&gt;.
So for the following &lt;code&gt;deps.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The libraries used would be &lt;code&gt;A&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;, transient &lt;code&gt;C&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt; from &lt;code&gt;A&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, for the following &lt;code&gt;deps.fnl&lt;/code&gt; (&lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; appear in the reverse order):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The libraries used would be &lt;code&gt;A&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;, transient &lt;code&gt;C&lt;/code&gt; version &lt;code&gt;2&lt;/code&gt; from &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt; version &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This wasn&amp;rsquo;t clear enough, and could introduce unexpected results when editing &lt;code&gt;deps.fnl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, adding another dependency before &lt;code&gt;A&lt;/code&gt; that (unknowingly) also depends on yet another version of &lt;code&gt;C&lt;/code&gt; would override the version for the project.&lt;/p&gt;
&lt;p&gt;At first, I was thinking about using &lt;code&gt;:exlusions&lt;/code&gt; key to specify that we want to exclude certain transient dependencies, but it also introduced the need to do this at arbitrary depth:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:exclusions&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;]}]]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we would still not know what version of &lt;code&gt;C&lt;/code&gt; we&amp;rsquo;re using.&lt;/p&gt;
&lt;p&gt;So instead, conflict resolution works by specifying the specific version of dependency &lt;code&gt;C&lt;/code&gt; at the same level as &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way the project author is in full control of what versions will be used.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--allow-conflicts&lt;/code&gt; flag is no more.
By default, conflicts are checked, and the only way to resolve conflicts is either to update the library in question, or override it at the root level.&lt;/p&gt;
&lt;h3 id=&#34;conflict-resolution-is-now-module-based&#34;&gt;Conflict resolution is now module-based&lt;/h3&gt;
&lt;p&gt;Another new feature I&amp;rsquo;m pretty excited about is module-based conflict resolution.
In the &lt;code&gt;0.1.0&lt;/code&gt; version of &lt;code&gt;deps&lt;/code&gt; it was not possible to detect conflicts when something is a fork.&lt;/p&gt;
&lt;p&gt;What I mean by that is, say, I have a library: &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; and someone decides to fork it to change something or fix a bug.
They add the following to their project &lt;code&gt;deps.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/some-fork/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;98e8680b46a777f9ddcff9e761b782ec6bf077f5&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main question thus was - what &lt;code&gt;async.fnl&lt;/code&gt; implementation would actually be loaded?
We could answer this question if &lt;code&gt;:deps&lt;/code&gt; was a list instead of a table because the ordering would rule out and &lt;code&gt;(require :io.gitlab.andreyorst.async)&lt;/code&gt; would load the first library.
However, with deps stored as a map, we would have gotten different implementations each time because key hashing is randomized.&lt;/p&gt;
&lt;p&gt;The problem is - previously &lt;code&gt;deps&lt;/code&gt; didn&amp;rsquo;t see this as a conflict.
These two libraries are the &lt;em&gt;same library&lt;/em&gt; but different &lt;em&gt;projects&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now, instead of comparing just library names (URLs in this case) and versions (SHAs for Git dependencies), &lt;code&gt;deps&lt;/code&gt; also compares exported modules.
So we can detect the conflict because both libraries export &lt;code&gt;io.gitlab.andreyorst.async&lt;/code&gt; module.
If the person who forked the library chooses to change the module name to &lt;code&gt;io.gitlab.some-fork.async&lt;/code&gt; instead, there won&amp;rsquo;t be a conflict, as this is now a properly different library.&lt;/p&gt;
&lt;p&gt;The example above is unlikely to happen as is, but if some library uses a fork as a transient dependency this might happen.
This was pointed out to me by Ambrose Bonnaire-Sergeant off the mailing list, and we&amp;rsquo;ve come up with this solution.&lt;/p&gt;
&lt;h3 id=&#34;luarocks--transient--dependencies&#34;&gt;Luarocks (transient) dependencies&lt;/h3&gt;
&lt;p&gt;Another problem with transient dependencies is the fact that Luaorcks dependency manifests are very lax about versions of the transient dependencies.
Usually, you would see just library names, and sometimes version ranges.
For example, here&amp;rsquo;s a fragment from the &lt;a href=&#34;https://luarocks.org/manifests/leafo/lapis-1.16.0-1.rockspec&#34; target=&#34;_blank&#34;&gt;lapis&lt;/a&gt; library manifest describing dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dependencies = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ansicolors&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;argparse&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;etlua&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loadkit&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lpeg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-cjson&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luaossl&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pgmoon&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;pgmoon&lt;/code&gt; dependency itself depends on &lt;code&gt;lpeg&lt;/code&gt;.
So Luarocks default strategy is to pull the latest available version of the library.&lt;/p&gt;
&lt;p&gt;This makes conflict resolution harder, because &lt;code&gt;deps.fnl&lt;/code&gt; requires specifying a concrete version of any dependency.
Paired with the fact that Luarocks silently overrides already installed dependencies when you give it a specific version to install, and the fact that &lt;code&gt;deps.fnl&lt;/code&gt; is now unordered, the only way to get deterministic versions from Luarocks was to ask users to specify all of the transient dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lapis&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.16.0-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loadkit&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.1.0-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;etlua&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.3.0-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.0-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-cjson&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2.1.0.10-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;argparse&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.7.1-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lpeg&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.1.0-2&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ansicolors&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.0.2-3&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2.2.1-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pgmoon&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.16.0-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dependencies&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lpeg&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.1.0-2&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luaossl&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;20220711-0&amp;#34;&lt;/span&gt;}}}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;:dependencies&lt;/code&gt; key is akin to the &lt;code&gt;dependencies&lt;/code&gt; map in the rock manifest.&lt;/p&gt;
&lt;p&gt;The conflict resolution works exactly the same.&lt;/p&gt;
&lt;h3 id=&#34;runtime-library-manipulation-with-deps-dot-add-lib-and-sync-deps&#34;&gt;Runtime library manipulation with &lt;code&gt;deps.add-lib&lt;/code&gt;, and &lt;code&gt;sync-deps&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Something that escaped my previous announcement, because it was developed a bit later is that it is now possible to add libraries while working on the application without restarting the REPL.
When the REPL is started via the &lt;code&gt;deps --repl&lt;/code&gt; command, a new &lt;code&gt;deps&lt;/code&gt; module is available:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:_VERSION&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.2.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-lib&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560a243c2990&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-libs&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560a245b5820&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sync-deps&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560a246d8d50&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thus, if you&amp;rsquo;re working on some project and in need of a new dependency, or want to compare a few and choose which one to use, you can quickly do so in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deps.add-libs&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bump&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.1.7-1&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;anim8&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v2.3.1-1&amp;#34;&lt;/span&gt;}})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bump&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;anim8&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deps.add-lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;penlight&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.14.0-2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dependencies&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luafilesystem&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.8.0-1&amp;#34;&lt;/span&gt;}}})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.input&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.path&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.array2d&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.compat&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.luabalanced&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.pretty&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.import_into&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.dir&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.func&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.Map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.comprehension&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.app&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.seq&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.sip&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.stringx&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.class&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.Date&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.strict&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.template&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.types&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.permute&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.MultiMap&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.text&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.utils&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.OrderedMap&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.xml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.url&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.tablex&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.test&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.lapp&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.List&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.Set&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.operator&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.data&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.lexer&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.config&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.init&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pl.stringio&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lfs&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The returned value is a table of module names that are now available to &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, the &lt;code&gt;deps.fnl&lt;/code&gt; file can be edited, and changes can be synced into the running REPL via the &lt;code&gt;sync-deps&lt;/code&gt; call.&lt;/p&gt;
&lt;h3 id=&#34;new-flags&#34;&gt;New flags&lt;/h3&gt;
&lt;p&gt;Several new flags were added.&lt;/p&gt;
&lt;h4 id=&#34;tree&#34;&gt;&lt;code&gt;--tree&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Prints the dependency tree, outlining what dependencies are on your path, and what transient dependencies are brought by each dependency:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[&amp;#34;lapis&amp;#34; &amp;#34;1.16.0-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [[&amp;#34;argparse&amp;#34; &amp;#34;0.7.1-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;luaossl&amp;#34; &amp;#34;20220711-0&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;pgmoon&amp;#34; &amp;#34;1.16.0-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [[&amp;#34;lpeg&amp;#34; &amp;#34;1.1.0-2&amp;#34;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;date&amp;#34; &amp;#34;2.2.1-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;luasocket&amp;#34; &amp;#34;3.1.0-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;loadkit&amp;#34; &amp;#34;1.1.0-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;ansicolors&amp;#34; &amp;#34;1.0.2-3&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;lpeg&amp;#34; &amp;#34;1.1.0-2&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;etlua&amp;#34; &amp;#34;1.3.0-1&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&amp;#34;lua-cjson&amp;#34; &amp;#34;2.1.0.10-1&amp;#34;]]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;andreyorst/fennel-test&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;#34;9aae4dd52be1f5dd1ee97e61c639e6c5a2f9afee&amp;#34;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;fennel-ls&#34;&gt;&lt;code&gt;--fennel-ls&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;deps&lt;/code&gt; script is now able to create or update an existing configuration for the &lt;a href=&#34;https://git.sr.ht/~xerool/fennel-ls/&#34; target=&#34;_blank&#34;&gt;fennel-ls&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;When calling &lt;code&gt;deps --fennel-ls&lt;/code&gt; a &lt;code&gt;flsproject.fnl&lt;/code&gt; file will be created if it doesn&amp;rsquo;t exist already.
This file will contain all of the PATH-related data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test/?.fnl;.deps/git/andreyorst/fennel-test/9aae4dd52be1f5dd1ee97e61c639e6c5a2f9afee/src/?/init.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lua-version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua54&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.deps/git/andreyorst/fennel-test/9aae4dd52be1f5dd1ee97e61c639e6c5a2f9afee/src/?/init.fnlm&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;profiles&#34;&gt;&lt;code&gt;--profiles&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Another new feature - profiles!
Before this flag existed profiles were kind of possible by using &lt;code&gt;--merge&lt;/code&gt; and additional &lt;code&gt;deps.fnl&lt;/code&gt; files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; dev-deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having these two files, a final deps map can be obtained with &lt;code&gt;deps --merge dev-deps.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; output of `deps --merge dev-deps.fnl --show`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro&lt;/span&gt; {}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works, but semantically it is a bit unclear.
To know that the development &amp;ldquo;profile&amp;rdquo; exists you need to actively look for it in the project files.
Multiple such profiles also pile up in the project, which is not great.&lt;/p&gt;
&lt;p&gt;Now, this can be done a bit more consistently with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; deps.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:profiles&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;]}}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the same final deps map can be obtained with &lt;code&gt;deps --profiles dev&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; output of `deps --profiles dev --show`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;72a74394f89fdaf15abf11f33752a07e9e0bee91&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;252ea2474cb7399020e6922f700a5190373e6f98&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tests/?.fnl&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lua&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro&lt;/span&gt; {}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--merge&lt;/code&gt; flag is here to stay for compatibility.
Maybe there are other use cases for it too, so it won&amp;rsquo;t be removed unless deemed unnecessary.
Moreover, &lt;code&gt;--profiles&lt;/code&gt; actually supports multiple comma-separated profile names, so it is much more compact compared to &lt;code&gt;--merge&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ deps --profiles dev,test,doc ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ deps --merge dev-deps.fnl --merge test-deps.fnl --merge doc-deps.fnl ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;upcoming-work&#34;&gt;Upcoming work&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll probably take a short break from working on &lt;code&gt;deps&lt;/code&gt; for a while, or at least I won&amp;rsquo;t work on it as actively.
Both to let it settle a bit, give it time to gather some feedback, and let me rest a bit too.
I&amp;rsquo;m feeling good about what I did so far, and &lt;code&gt;deps&lt;/code&gt; in my opinion is out of the alpha stage for sure.
So I think it can be safely used in other projects, and I&amp;rsquo;m still open for feedback!&lt;/p&gt;
&lt;p&gt;As for plans, I have something I want to experiment with.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve started outlining an interface for custom backend implementations.
Right now there are only two backends: Git and Luarocks, but if the community desires, I&amp;rsquo;ll extend &lt;code&gt;deps&lt;/code&gt; in such a way that custom backends could be added via some sort of a plugin system.
Thus other ways to download and add dependencies would be possible.
For example, recently I learned that some Lua libraries exist only in SVN.
There may be others that are only available through GNU Bazaar, the new hot &lt;a href=&#34;https://github.com/jj-vcs/jj&#34; target=&#34;_blank&#34;&gt;Jujutsu VCS&lt;/a&gt;, or maybe some use Mercurial, I don&amp;rsquo;t know!&lt;/p&gt;
&lt;p&gt;Additionally, I think it is safe to say, that using version control systems for libraries is not a great idea, so I might start working on a dependency packaging system for Fennel libraries that we could later upload to some package archive.
Thinking of a name - Fennel Bulbs sounds fun!&lt;/p&gt;
&lt;p&gt;Dependency building needs to be changed to be a bit more robust.
Right now I think it should work fine, but probably only on *nix-based systems.
Windows support for &lt;code&gt;deps.fnl&lt;/code&gt; is there, but completely untested.
So if any Fennel users happen to do their stuff on Windows - let me know if it works, please!&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for now.
Huge thanks to Phil Hagelberg, Ambrose Bonnaire-Sergeant, and Emma B. for the feedback and code reviews!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: deps.fnl 0.2.2 released&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 16 Feb 2025 06:30:00 +0300</pubDate>
    </item><item>
      <title>deps.fnl - a new dependency manager for Fennel projects</title>
      <link>https://andreyor.st/posts/2025-01-10-depsfnl-a-new-dependency-manager-for-fennel-projects/</link>
      <guid>https://andreyor.st/posts/2025-01-10-depsfnl-a-new-dependency-manager-for-fennel-projects/</guid>
      <description>&lt;p&gt;I&amp;rsquo;d like to present a new project, aimed at one of the areas where the Fennel ecosystem can be improved - project dependency management.&lt;/p&gt;
&lt;p&gt;Other programming languages have tools to pull in, build, and load external dependencies.
Java has Maven, Clojure has Leiningen and other projects like this, Python has Pip and Poetry, and Lua has Luarocks.
All these tools provide ways for pulling in dependencies concerning how the language is organized.&lt;/p&gt;
&lt;p&gt;Since Fennel runs on Lua, we could use Luarocks, but, well, it&amp;rsquo;s not really good.
It has a lot of design problems and doesn&amp;rsquo;t fit for Fennel for a number of reasons, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is tailored for Lua dependencies only, so shipping Fennel libraries would require AOT compiling them to Lua;&lt;/li&gt;
&lt;li&gt;Luarocks only knows how to build &lt;code&gt;LUA_PATH&lt;/code&gt; and &lt;code&gt;LUA_CPATH&lt;/code&gt;, but Fennel requires &lt;code&gt;FENNEL_PATH&lt;/code&gt; and more importantly &lt;code&gt;FENNEL_MACRO_PATH&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Shipping macros is hard or impossible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;a-few-notes-on-why-i-decided-to-make-a-dependency-manager&#34;&gt;A few notes on why I decided to make a dependency manager&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve made a lot of libraries for Fennel and encountered various problems with shipping these libraries to users.&lt;/p&gt;
&lt;p&gt;Most of the Fennel libraries I write feature user-exposed macros, which means that the library can&amp;rsquo;t be shipped as a single file most of the time.
I did find a workaround for that eventually, but it still poses some interesting challenges for library writers.&lt;/p&gt;
&lt;p&gt;Another problem I encountered are libraries that need other libraries to work.
Some of my libraries depend on other libraries I made, and thus I either need to include them in the source code directly for shipping or do some other trickery.
And libraries depending on other libraries (transient dependencies) could potentially conflict with other dependencies in the project.&lt;/p&gt;
&lt;p&gt;Finally, multifile libraries that can&amp;rsquo;t be compiled into a single file, since they have multiple modules that serve as entry points are hard to ship because users will have to properly set up &lt;code&gt;PATH&lt;/code&gt; in their project.&lt;/p&gt;
&lt;p&gt;So I made &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;deps.fnl&lt;/a&gt; to solve these problems.&lt;/p&gt;
&lt;h2 id=&#34;deps-dot-fnl&#34;&gt;&lt;code&gt;deps.fnl&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This project consists of a single script, called &lt;code&gt;deps&lt;/code&gt;, that works as a drop-in replacement for the fennel executable.
This means that you can call &lt;code&gt;deps&lt;/code&gt; with any arguments that you specify to Fennel, and it will work transparently.
In other words:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deps --require-as-include --compile file.fnl &amp;gt; file.lua
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the main thing that &lt;code&gt;deps&lt;/code&gt; was designed to do is to set up the environment for your project.
When the &lt;code&gt;deps.fnl&lt;/code&gt; file is present in the project, the &lt;code&gt;deps&lt;/code&gt; script analyzes this file and pulls in all of the specified libraries, sets all required &lt;code&gt;PATH&lt;/code&gt; variables, like &lt;code&gt;LUA_PATH&lt;/code&gt;, &lt;code&gt;LUA_CPATH&lt;/code&gt;, &lt;code&gt;FENNEL_PATH&lt;/code&gt;, and &lt;code&gt;FENNEL_MACRO_PATH&lt;/code&gt;, and launches &lt;code&gt;fennel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s a &lt;code&gt;deps.fnl&lt;/code&gt; for my &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/async.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a83b13b397fdfab3ebf7f17a16d21a7ec2674ceb&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/json.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bfb8d7d03c26619768eefaa47782a3e95dbe5156&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/reader.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3ff2bc790c8b7922267af5712a64a14572a172cf&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;luasocket&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;3.0rc1-2&amp;#34;&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/?/init.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, this project depends on four libraries: &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt;, &lt;a href=&#34;https://gitlab.com/andreyorst/json.fnl&#34; target=&#34;_blank&#34;&gt;json.fnl&lt;/a&gt;, &lt;a href=&#34;https://gitlab.com/andreyorst/reader.fnl&#34; target=&#34;_blank&#34;&gt;reader.fnl&lt;/a&gt;, and &lt;a href=&#34;https://w3.impa.br/~diego/software/luasocket/home.html&#34; target=&#34;_blank&#34;&gt;luasocket&lt;/a&gt;.
Previously I had to vendor these dependencies in the repository, and instruct people how to install &lt;code&gt;fnl-http&lt;/code&gt; and use it as a library.&lt;/p&gt;
&lt;p&gt;Moreover, &lt;code&gt;fnl-http&lt;/code&gt; is a multi-file library, so manually setting up &lt;code&gt;PATH&lt;/code&gt; for it and all of its dependencies is not a pleasant task.
But with deps you can use this library in your project by placing this deps.fnl file at your project root:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fnl-http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ea885a8c767a627206126cc36f1befb1a2d71850&amp;#34;&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?.fnl&amp;#34;&lt;/span&gt;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then just call &lt;code&gt;deps --repl&lt;/code&gt;, and you&amp;rsquo;re good to go:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deps&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;--repl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/fnl-http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/async.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/json.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repo&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;https&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;://gitlab.com/andreyorst/reader.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;luasocket&lt;/span&gt; 3.0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rc1-2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Welcome&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Fennel&lt;/span&gt; 1.5&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.1-dev&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PUC&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lua&lt;/span&gt; 5.4&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Use&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;help&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;see&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;available&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;commands.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connect&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605682104e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:delete&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568bc64c0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605685315c0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:head&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605689c9ca0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:options&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605682b0a20&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:patch&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605687d8f40&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:post&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568c40270&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:put&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5605681d9d80&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568b37450&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x560568580320&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the output above after analyzing the project&amp;rsquo;s &lt;code&gt;deps.fnl&lt;/code&gt; the &lt;code&gt;deps&lt;/code&gt; script proceeds to download dependencies.
The project&amp;rsquo;s only dependency is fnl-http, but after downloading it, the &lt;code&gt;deps&lt;/code&gt; script check if there&amp;rsquo;s a &lt;code&gt;deps.fnl&lt;/code&gt; in the root of the repository.
Since there is, it proceeds to download all transient dependencies.
Calling &lt;code&gt;deps --repl&lt;/code&gt; the second time would not download anything, unless new dependencies were added to the &lt;code&gt;deps.fnl&lt;/code&gt; file or hashes/version were changed.&lt;/p&gt;
&lt;p&gt;After processing all of the dependencies the REPL is started as requested, and the library is ready to be used.&lt;/p&gt;
&lt;h2 id=&#34;dependency-types&#34;&gt;Dependency types&lt;/h2&gt;
&lt;p&gt;Dependencies can be of two types - &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;rock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Git dependencies are just a link to the repository and a commit hash to checkout.
Until we have some kind of a registry and a way to package libraries for downloading this is the best we can do.
But as seen above, this already makes using libraries a lot simpler.&lt;/p&gt;
&lt;p&gt;Rock dependencies are processed with Luarocks.
Yes, &lt;code&gt;deps&lt;/code&gt; wraps not only the Fennel executable but Luarocks as well.
Luarocks is fine enough to be used like this and provides enough command-line arguments for &lt;code&gt;deps&lt;/code&gt; needs.&lt;/p&gt;
&lt;p&gt;All of the dependencies are stored in the project&amp;rsquo;s root unless requested elsewhere.
I decided not to go the &lt;code&gt;.m2&lt;/code&gt; route.
One reason for that is the fact, that Luarocks can&amp;rsquo;t install two versions of the same library into a single &amp;ldquo;tree&amp;rdquo;, as they call it.
Instead, it overrides any library already present in the tree.
This is probably related to how the &lt;code&gt;LUA_PATH&lt;/code&gt; is constructed by Luarocks.&lt;/p&gt;
&lt;p&gt;Speaking of &lt;code&gt;PATH=⁣s. The =deps.fnl&lt;/code&gt; file contains a mandatory field &lt;code&gt;:paths&lt;/code&gt;, that contains a table.
This table specifies the project&amp;rsquo;s path configuration.
Each library may require a different path configuration, and when &lt;code&gt;deps&lt;/code&gt; script processes a said &lt;code&gt;deps.fnl&lt;/code&gt; file, it reads the path table and constructs the final &lt;code&gt;PATH&lt;/code&gt; for your project.&lt;/p&gt;
&lt;p&gt;You can analyze the path generated for the project with &lt;code&gt;deps --path&lt;/code&gt;.
It prints the path to standard out in a format similar to &lt;code&gt;luarocks path&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, some Git repositories may not use &lt;code&gt;deps.fnl&lt;/code&gt;, but it is still possible to manage them with &lt;code&gt;deps.fnl&lt;/code&gt;.
For example, my library fennel-test doesn&amp;rsquo;t yet feature a &lt;code&gt;deps.fnl&lt;/code&gt; file, but the &lt;code&gt;deps&lt;/code&gt; script itself uses it for testing.
To make this work, you can specify &lt;code&gt;:paths&lt;/code&gt; field for each dependency:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/fennel-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sha&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;01ea080dc8176512c5890462252c5bf214baf137&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?.fnl&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:macro&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?.fnl&amp;#34;&lt;/span&gt;]}}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:paths&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thus, we can even pull in pure Lua dependencies, and specify the &lt;code&gt;:paths&lt;/code&gt; table with something like &lt;code&gt;{:lua [&amp;quot;?.lua&amp;quot;]}&lt;/code&gt;, and &lt;code&gt;deps&lt;/code&gt; will set everything up.&lt;/p&gt;
&lt;p&gt;You can read more information on the &lt;code&gt;deps.fnl&lt;/code&gt; file format, and &lt;code&gt;deps&lt;/code&gt; script usage in the project&amp;rsquo;s &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl/-/blob/main/README.md&#34; target=&#34;_blank&#34;&gt;readme&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;i-need-feedback&#34;&gt;I need feedback&lt;/h2&gt;
&lt;p&gt;I have high hopes for this project, and I&amp;rsquo;m looking for feedback.
If you&amp;rsquo;re working on some application that requires external dependencies, give &lt;code&gt;deps.fnl&lt;/code&gt; a shot.
If you&amp;rsquo;re a library maker like me, consider using &lt;code&gt;deps.fnl&lt;/code&gt; so your users have an easier way of using your work.
You can submit feedback either via email, or &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl&#34; target=&#34;_blank&#34;&gt;GitLab&lt;/a&gt; &lt;a href=&#34;https://gitlab.com/andreyorst/deps.fnl/-/issues&#34; target=&#34;_blank&#34;&gt;issues&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If the project gets enough traction and is to community&amp;rsquo;s satisfaction, Phil and I are discussing the possibility of including this into Fennel itself, so no installation would be required.
Since &lt;code&gt;deps&lt;/code&gt; is already a drop-in replacement for &lt;code&gt;fennel&lt;/code&gt;, once &lt;code&gt;deps&lt;/code&gt; is a part of the fennel executable, all commands from the above would work with just fennel itself.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I hope this project will be useful to you!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: deps.fnl - a new dependency manager for Fennel projects&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 10 Jan 2025 00:47:00 +0300</pubDate>
    </item><item>
      <title>Tiny OOP in Lua</title>
      <link>https://andreyor.st/posts/2025-01-07-tiny-oop-in-lua/</link>
      <guid>https://andreyor.st/posts/2025-01-07-tiny-oop-in-lua/</guid>
      <description>&lt;p&gt;Recently I was participating in a conversation about popular programming languages and I brought up Lua.
I was met with a response like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lua?
Can you even do anything with this language?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The conversation then shifted towards discussing modern dynamic languages, mostly Python, and how it gives you everything Java does without being as complicated as Java.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a Python fan - in fact, I think Python is a badly designed language and should be avoided.
But people tend to like it for some reason.
I also think that Lua is a much better language and it&amp;rsquo;s worth considering it before jumping to Python or alternatives.&lt;/p&gt;
&lt;p&gt;I do agree that Lua is much smaller than Python, and it can do less by itself, as there are no batteries included in the language.
But it also means that you can bring in only what you need for the project.&lt;/p&gt;
&lt;p&gt;And Lua is extremely flexible too.
When the conversation shifted towards discussing Python, one particular thing was discussed the most - Python is object-oriented.
Lua isn&amp;rsquo;t, as there are no classes, no inheritance, or such.
I brought up Lua again in the conversation, saying that it&amp;rsquo;s quite easy to add object orientation to Lua if you need it for your project.
People were skeptical so I decided to write this post.&lt;/p&gt;
&lt;p&gt;Most of the code here I wrote on my phone while guys were arguing about Python, so I wasn&amp;rsquo;t participating in the conversation much.
After I was done, I showed them the following example, but the only response I got was a yet again skeptical &amp;ldquo;neat&amp;rdquo;.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Neat.&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2025-01-07-tiny-oop-in-lua/sad.jpg&#34;/&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;So here&amp;rsquo;s a basic OOP-style code in Lua.&lt;/p&gt;
&lt;p&gt;First, we need a class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; Shape = {}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s just a table, but now let&amp;rsquo;s add a &lt;code&gt;new&lt;/code&gt; method to it and do some metatable trickery:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Shape&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new&lt;/span&gt;(obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.__index = self
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; setmetatable(obj &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; {}, self)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can create an object like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; s = Shape:new{}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s still a table, but it has &lt;code&gt;Shape&lt;/code&gt; as it&amp;rsquo;s metatable.
It means that we can add methods directly to a class, and all objects would share them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Shape&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setOrigin&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.x, self.y = x, y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Shape&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getOrigin&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.x, self.y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can set the shape&amp;rsquo;s origin, and then obtain it with these methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s:setOrigin(1, 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(s:getOrigin()) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1, 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Note on &lt;code&gt;self&lt;/code&gt;: in Lua &lt;code&gt;self&lt;/code&gt; is an ordinary variable name, that is implicitly declared when we use method declaration syntax.
In other words, these two function definitions are the same thing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Shape&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getOrigin&lt;/span&gt;() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- the colon after Shape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.x, self.y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Shape&lt;/span&gt;.&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getOrigin&lt;/span&gt;(self) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- the dot after Shape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.x, self.y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s just a bit more convenient to write &lt;code&gt;Class:method(...)&lt;/code&gt; than &lt;code&gt;Class.method(self, ...)&lt;/code&gt; when defining a function.
And when we&amp;rsquo;re calling a method with &lt;code&gt;:&lt;/code&gt; instead of &lt;code&gt;.&lt;/code&gt; it automatically passes the object as the first argument.
So again, these are the same:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s:setOrigin(1, 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s.setOrigin(s, 1, 1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;But what makes objects special is the ability to build upon objects using inheritance.
So let&amp;rsquo;s create a new class that inherits all of the methods of &lt;code&gt;Shape&lt;/code&gt; and provides some new on its own:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; Rectangle = Shape:new{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Rectangle&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setWidth&lt;/span&gt;(width)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.width = width
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Rectangle&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setHeight&lt;/span&gt;(height)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.height = height
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Rectangle&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;area&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.width * self.height
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve defined a new class &lt;code&gt;Rectangle&lt;/code&gt; that inherits all of the &lt;code&gt;Shape&lt;/code&gt; methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; rect = Rectangle:new{width = 2, height = 4}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rect:setOrigin(3, 4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(rect:getOrigin()) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3, 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(rect:area())      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how this works:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Rectangle&lt;/code&gt; inherits &lt;code&gt;new&lt;/code&gt; from &lt;code&gt;Shape&lt;/code&gt; like any other method.
This time, however, when &lt;code&gt;new&lt;/code&gt; executes, the &lt;code&gt;self&lt;/code&gt; parameter will refer to &lt;code&gt;Rectangle&lt;/code&gt;.
Therefore, the metatable of &lt;code&gt;rect&lt;/code&gt; will be &lt;code&gt;Rectangle&lt;/code&gt;, whose value at &lt;code&gt;__index&lt;/code&gt; is also &lt;code&gt;Rectangle&lt;/code&gt;.
So, &lt;code&gt;rect&lt;/code&gt; inherits from &lt;code&gt;Rectangle&lt;/code&gt;, which inherits from &lt;code&gt;Shape&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can go even further, defining a class that would inherit from &lt;code&gt;Rectangle&lt;/code&gt; but first, let&amp;rsquo;s add two helper functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;implements&lt;/span&gt;(obj, class)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; mt = getmetatable(obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= mt &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; class == mt.__index &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; implements(mt.__index, class)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;super&lt;/span&gt; (class)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (getmetatable(class) &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; {}).__index
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first function &lt;code&gt;implements&lt;/code&gt; is a predicate that checks if a given object implements a given class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(implements(rect, Shape))     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(implements(rect, Rectangle)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second function &lt;code&gt;super&lt;/code&gt; allows us to access a superclass of a class.
For example, to call a superclass method, like a constructor.&lt;/p&gt;
&lt;p&gt;We can create a new class that inherits from &lt;code&gt;Rectangle&lt;/code&gt; and use it to alter the inherited constructor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; Square = Rectangle:new{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Square&lt;/span&gt;:&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;new&lt;/span&gt;(obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.__index = self
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; obj = super(self):new{width = obj.width, height = obj.width}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; setmetatable(obj, self)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that &lt;code&gt;Square&lt;/code&gt; implements all of the methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; square = Square:new{width = 10}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(implements(square, Shape))     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(implements(square, Rectangle)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(implements(square, Square))    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;square:setOrigin(5, 6)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(square:getOrigin()) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 5, 6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(square:area()) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This isn&amp;rsquo;t a new kind of trick though.
All of this was greatly described in the &lt;a href=&#34;https://www.lua.org/pil/16.2.html&#34; target=&#34;_blank&#34;&gt;Programming In Lua book&lt;/a&gt;.
In fact, I straight up took the explanation from this page and adjusted class names in it to represent the code on this page.&lt;/p&gt;
&lt;p&gt;Now, of course, this leaves out a lot of stuff like encapsulation, and multiple inheritance, but you can build on this simple concept further if you really need to.
Moreover, there are multiple ways of achieving object orientation in Lua.
You can define the object&amp;rsquo;s methods in &lt;a href=&#34;https://technomancy.us/197&#34; target=&#34;_blank&#34;&gt;five different ways&lt;/a&gt;.
But in my practice even what I did here is way more than I ever needed.&lt;/p&gt;
&lt;p&gt;What I wanted to show here is the flexibility that Lua provides you with.
If you need something that&amp;rsquo;s missing in pure Lua, the same pure Lua probably has a way to add that to the language.
Over the years I&amp;rsquo;ve created lazy sequences, immutable data structures, and asynchronous channels all in pure Lua.
With C modules you can add even crazier stuff.&lt;/p&gt;
&lt;p&gt;Lua is a very capable language.
The community made a lot of libraries.
If you want so-called &amp;ldquo;batteries&amp;rdquo; there&amp;rsquo;s &lt;a href=&#34;https://lunarmodules.github.io/Penlight/&#34; target=&#34;_blank&#34;&gt;Penlight&lt;/a&gt;.
If you&amp;rsquo;re making games, you have LÖVE2D that gives you its own batteries and a plethora of small Lua libraries for game-making are available too.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not a fan of the syntax or want more features in the base language you can choose amongst other languages compile to Lua.
For example, there&amp;rsquo;s &lt;a href=&#34;https://moonscript.org/&#34; target=&#34;_blank&#34;&gt;MoonScript&lt;/a&gt; which is whitespace-based like Python.
Or there are &lt;a href=&#34;https://fennel-lang.org/&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; and &lt;a href=&#34;https://urn-lang.com/&#34; target=&#34;_blank&#34;&gt;Urn&lt;/a&gt; if you&amp;rsquo;re into lisps.
And probably &lt;a href=&#34;https://github.com/hengestone/lua-languages&#34; target=&#34;_blank&#34;&gt;other languages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lua is fast, has a small footprint, is easily embeddable, and is very flexible.
It&amp;rsquo;s a shame it&amp;rsquo;s not taken seriously most of the time.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Tiny OOP in Lua&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 07 Jan 2025 23:39:00 +0300</pubDate>
    </item><item>
      <title>2024 Recap</title>
      <link>https://andreyor.st/posts/2024-12-29-2024-recap/</link>
      <guid>https://andreyor.st/posts/2024-12-29-2024-recap/</guid>
      <description>&lt;p&gt;What a year!&lt;/p&gt;
&lt;p&gt;Not as productive as last year, with only 18 posts this time (19 including this one), but I decided to post less for several reasons.&lt;/p&gt;
&lt;p&gt;The first one, is that right at the start of this year I had some events in my personal life that had an impact on my passion for writing.
I&amp;rsquo;ve pretty much recovered since, but this explains some quietness in the blog during February.&lt;/p&gt;
&lt;p&gt;The second one is that I felt a strong burnout from programming.
I do programming for a living, it&amp;rsquo;s also my hobby, and they say &amp;ldquo;Find A Job You Love And You&amp;rsquo;ll Never Work A Day In Your Life&amp;rdquo;, but it doesn&amp;rsquo;t really work.
I love programming, really do, but it takes a lot of mental energy, and when you&amp;rsquo;re writing code for your whole day at work, and then come home and write code for your projects fatigue tends to pile up.
So I took a break from Fennel, and pretty much focused on Clojure and work stuff.
I also became a software architect this year and had to adjust my way of thinking a bit, so programming is no longer the main task at my job, and after a bit of rest, I was finally ready to go back to coding in my spare time.&lt;/p&gt;
&lt;p&gt;Before that happened though I bought myself a new guitar, and finally put up my first pedalboard!
Look at this beauty:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-12-29-2024-recap/guitar.jpg&#34;
         alt=&#34;Figure 1: Signal chain: Fender Telecaster → Polytune mini 3 → Yellow Comp → Pitch Box → Blues Driver → Mojomojo→ Flashback 2 → Hall of Fame 2 → Orange Crush 20 RT&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Signal chain: Fender Telecaster → Polytune mini 3 → Yellow Comp → Pitch Box → Blues Driver → Mojomojo→ Flashback 2 → Hall of Fame 2 → Orange Crush 20 RT&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Now I have three guitars - two electric guitars and a bass.
Getting a new guitar (the red one in the photo) was a great way to kick-start my interest in playing again, as I hadn&amp;rsquo;t done so for the last five or so years.
I bought a Japanese-manufactured Fender Telecaster made in 1993 for a moderate price, and I love it!
Plays and feels really great - I started to record myself again and made a small Telegram channel to post stuff about it, as I don&amp;rsquo;t really want to overwhelm GitLab with video files.
But here&amp;rsquo;s a short one:&lt;/p&gt;
&lt;p&gt;&lt;video controls loop&gt;&lt;source src=&#34;https://andreyor.st/2024-12-29-2024-recap/martian-winter.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  Intro cover of A Martian Winter by Angel Vivaldi (Warning - it&#39;s a bit loud)
&lt;/div&gt;
&lt;p&gt;I have used modelers for most of my time playing guitar, meaning that I would just plug my guitar into an audio interface, and add virtual implementations of various gear to shape my sound.
Like virtual overdrive and delay pedals, virtual amps, cab sims, etc.
So getting myself a real pedalboard was a step up from that in some sense, as I &lt;strong&gt;love&lt;/strong&gt; analog interfaces with knobs.
VSTs just didn&amp;rsquo;t do that for me.
However, I still use emulation when recording.&lt;/p&gt;
&lt;p&gt;Haven&amp;rsquo;t read much this year.
Mostly manga, but again, I was kinda overwhelmed with life stuff, so it was a small escape route for me.&lt;/p&gt;
&lt;p&gt;I had a lot of comments this year!
20 unique emails, not including replies and continued discussions.
That&amp;rsquo;s even more than there were posts!
I&amp;rsquo;m extremely glad that everyone commenting, it makes me feel much better about this blog being read, and not just existing for no one.&lt;/p&gt;
&lt;p&gt;Managed to participate in FennelConf 2024.
Prepared a talk about dependency management and my latest crazy package for Emacs &lt;a href=&#34;https://andreyor.st/posts/2024-12-20-extending-emacs-with-fennel/&#34;&gt;require-fennel.el&lt;/a&gt;.
It was cool as always, and I&amp;rsquo;m happy to be a part of this amazing community.&lt;/p&gt;
&lt;p&gt;Now, for the next year, I have some plans.&lt;/p&gt;
&lt;p&gt;I finally decided to learn some music theory, so that&amp;rsquo;s one thing I&amp;rsquo;m excited about.
I&amp;rsquo;ve been playing guitar for more than ten years now, but only recently decided to &amp;ldquo;up my game&amp;rdquo; a bit, and actually figure out what I&amp;rsquo;m doing.&lt;/p&gt;
&lt;p&gt;As for this blog, and my projects - not so long ago I started working on a game in LÖVE2D, so maybe expect some dev-logs next year.
I don&amp;rsquo;t know though, making games is hard, and I only work on this project when I have the passion to, so it may take a long time for anything to be made public.
Maybe not even in the next year.
We&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s it!
I wish you a happy new year, and excited to see what the next year will bring us!
See you in 2025!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: 2024 Recap&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 29 Dec 2024 21:17:00 +0300</pubDate>
    </item><item>
      <title>Extending Emacs with Fennel</title>
      <link>https://andreyor.st/posts/2024-12-20-extending-emacs-with-fennel/</link>
      <guid>https://andreyor.st/posts/2024-12-20-extending-emacs-with-fennel/</guid>
      <description>&lt;p&gt;After watching this year&amp;rsquo;s EmacsConf and seeing Guile Emacs being resurrected I thought to myself - why limit ourselves to Guile?
Sure, Guile isn&amp;rsquo;t just a Scheme implementation, thanks to its compiler-tower-based design.
Other languages exist for Guile VM, such as Emacs Lisp, and Guile manual lists the following languages with various stages of completeness:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ECMAScript&lt;/li&gt;
&lt;li&gt;Brainfuck&lt;/li&gt;
&lt;li&gt;Lua&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, it would be nice, if Emacs could natively run all of these, but we have to understand, that Guile Lua is not PUC Lua.
Even LuaJIT has difficulties maintaining full compatibility with modern releases of Lua, having us stuck in the realm somewhere between Lua 5.1 and 5.2, while PUC Lua is already 5.4.
Future releases would bring more differences, making PUC Lua and Luajit diverge even more.&lt;/p&gt;
&lt;p&gt;And Lua is a &lt;em&gt;simple&lt;/em&gt; language, unlike something like JS, Ruby, or Python.
So I wouldn&amp;rsquo;t bet on the fact that Guile Ruby would be exactly the same as Ruby.
Maybe it will, but it&amp;rsquo;ll probably take years.&lt;/p&gt;
&lt;p&gt;So I thought, why not just use Lua as is?
The only thing we can&amp;rsquo;t do is to run Fennel functions from Emacs Lisp.
There were &lt;a href=&#34;https://github.com/edrx/emlua&#34; target=&#34;_blank&#34;&gt;attempts at bringing Lua VM into Emacs&lt;/a&gt;, running in the same process, however, as I know, it isn&amp;rsquo;t stable enough.&lt;/p&gt;
&lt;p&gt;However, Emacs can connect to a Fennel REPL, like it does for many other languages, such as Common Lisp or Clojure.
Sure, the language is running in a separate process, and this comes with a lot of nuances, but it&amp;rsquo;s still a possible route.&lt;/p&gt;
&lt;p&gt;So I made a small package: &lt;a href=&#34;https://github.com/andreyorst/require-fennel.el&#34; target=&#34;_blank&#34;&gt;require-fennel.el&lt;/a&gt;.
It&amp;rsquo;s capable of loading Fennel (or Lua) modules, and defining a set of functions on the Emacs side for every Fennel function in the module.&lt;/p&gt;
&lt;h2 id=&#34;running-fennel-from-emacs-lisp&#34;&gt;Running Fennel from Emacs Lisp&lt;/h2&gt;
&lt;p&gt;For example, we can load Fennel itself into Emacs like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we have all sorts of functions available, for example, here&amp;rsquo;s &lt;code&gt;fennel.eval&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(fcollect [i 1 10] (* i i))&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; [1 4 9 16 25 36 49 64 81 100]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, we can create a file &lt;code&gt;greet.fnl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;greet&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Greets NAME with a message.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hello, &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; from Fennel!&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and load it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;greet&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;greet&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Andrey&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &#34;Hello, Andrey from Fennel!&#34; will be displayed in the echo area of Emacs
&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s ask Emacs to describe the &lt;code&gt;greet&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;greet is a interpreted-function.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(greet NAME)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Greets NAME with a message.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, Emacs can show us the function signature and its documentation string obtained from Fennel.&lt;/p&gt;
&lt;p&gt;Unlike Emacs Lisp, Fennel functions support destructuring with special syntax based on how data literals are written in Fennel.
For example, let&amp;rsquo;s create a function that accepts a map, and destructures its keys:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Accepts a map with the X and Y keys, and adds them together.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After loading it in Emacs we&amp;rsquo;ll see the following documentation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo is a interpreted-function.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(foo ((:y . y) (:x . x)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Accepts a map with the X and Y keys, and adds them together.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I took some creative liberties and made it so Fennel hash tables are represented as association lists in Emacs Lisp.
So the &lt;code&gt;((:x . 1) (:y . 2))&lt;/code&gt; in Elisp is equal to &lt;code&gt;{:x 1 :y 2}&lt;/code&gt; in Fennel.
The argument list on the Emacs Lisp side is a bit unconventional, but I think that&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;The same goes for vector destructuring:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Adds two 2D vectors.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y0&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Emacs&amp;rsquo; documentation uses lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vec-add is a interpreted-function.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(vec-add (X0 y0) (X1 y1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Adds two 2D vectors.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I couldn&amp;rsquo;t make it work with vectors for some reason, and as can be seen, Emacs tries to upcase parameters, but it doesn&amp;rsquo;t recognize that &lt;code&gt;y0&lt;/code&gt; is also a parameter.
Probably fine, as such documentation would never be generated for Emacs Lisp functions.&lt;/p&gt;
&lt;p&gt;We can call such a function with both vectors and lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; [1 2] [1 2])   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; [2 4]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec-add&lt;/span&gt; &amp;#39;(1 2) &amp;#39;(1 2)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; [2 4]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s because Fennel doesn&amp;rsquo;t have a list datatype, it only has associative and sequential tables.
Thus I&amp;rsquo;m using Elisp vectors as the result type.&lt;/p&gt;
&lt;h3 id=&#34;data-conversion&#34;&gt;Data conversion&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s how conversion table when passing data from Elisp to Fennel:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Elisp&lt;/th&gt;
&lt;th&gt;Fennel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(1 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;((:foo . 1) (:bar . 2))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#s(hash-table test equal data (&amp;quot;foo&amp;quot; 1 &amp;quot;bar&amp;quot; 2))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:foo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&#39;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And here&amp;rsquo;s the conversion table when receiving data from Fennel in Emacs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fennel&lt;/th&gt;
&lt;th&gt;Elisp&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[1 2 3]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{:foo 1 :bar 2}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;((:foo . 1) (:bar . 2))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(values 1 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(1 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(fn [])&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(lambda (&amp;amp;rest args) ...)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;userdata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#&amp;lt;udata: 0x55b66bd6ac28&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nil&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A small note about hash tables and multiple value returns.
As can be seen, both are returned as lists.
I specifically chose the cons notation for association lists, i.e. &lt;code&gt;(a . b)&lt;/code&gt; because this way we can tell apart hash tables and mustivalues.
There are no cons cells in Fennel, so no other data structure will be represented like that.&lt;/p&gt;
&lt;p&gt;Because multiple values are returned as lists, we have to call apply, if we wish to compose two Fennel functions.
In other words, in Fennel we can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt; 1 2 3)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  &lt;code&gt;fr.fnl&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;In Elisp, however, we would have to do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fr.first&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fr.rest&lt;/span&gt; 1 2 3)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we were to call it as &lt;code&gt;(fr.first (fr.rest 1 2 3))&lt;/code&gt; the result would be &lt;code&gt;[2 3]&lt;/code&gt;, because &lt;code&gt;fr.rest&lt;/code&gt; returned a list of return values, and lists are converted to vectors or hash maps depending on their structure.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the basic gist of this package.&lt;/p&gt;
&lt;h3 id=&#34;more-examples&#34;&gt;More examples&lt;/h3&gt;
&lt;p&gt;After implementing it I was like a kid in a toy store.
With a childish grin, I started loading all my crazy Fennel libraries that I made over the years.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s &lt;code&gt;cljlib&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib.conj&lt;/span&gt; [1] 2) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;=&amp;gt; [1 2]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, here&amp;rsquo;s a JSON parser I made:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.decode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;foo\&amp;#34;: [1, 2, 3]}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ((&amp;#34;foo&amp;#34; . [1 2 3]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.encode&lt;/span&gt; &amp;#39;((&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; . [1 2 3])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;{\&amp;#34;foo\&amp;#34;: [1, 2, 3]}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s a crazy one - I&amp;rsquo;m loading my Fennel port of a Clojure library clj-http into Emacs, and calling it from Elisp:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.gitlab.andreyorst.fnl-http&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.gitlab.andreyorst.fnl-http.client&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; nested module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; &amp;#39;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:as&lt;/span&gt; . &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:json&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; ((&amp;#34;headers&amp;#34; . ((&amp;#34;Content-Length&amp;#34; . &amp;#34;198&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Access-Control-Allow-Credentials&amp;#34; . t)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Access-Control-Allow-Origin&amp;#34; . &amp;#34;*&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Content-Type&amp;#34; . &amp;#34;application/json&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Connection&amp;#34; . &amp;#34;keep-alive&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Server&amp;#34; . &amp;#34;gunicorn/19.9.0&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                   (&amp;#34;Date&amp;#34; . &amp;#34;Mon, 16 Dec 2024 22:56:35 GMT&amp;#34;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;reason-phrase&amp;#34; . &amp;#34;OK&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;length&amp;#34; . 198)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;protocol-version&amp;#34; . ((&amp;#34;name&amp;#34; . &amp;#34;HTTP&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                            (&amp;#34;minor&amp;#34; . 1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                            (&amp;#34;major&amp;#34; . 1)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;request-time&amp;#34; . 214)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;trace-redirects&amp;#34; . [])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;status&amp;#34; . 200)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (&amp;#34;body&amp;#34; . ((&amp;#34;args&amp;#34; . [])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                (&amp;#34;headers&amp;#34; . ((&amp;#34;Host&amp;#34; . &amp;#34;httpbin.org&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                              (&amp;#34;X-Amzn-Trace-Id&amp;#34; . &amp;#34;Root=1-6760b023-39ca8e413573df5d14d09486&amp;#34;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;                (&amp;#34;url&amp;#34; . &amp;#34;http://httpbin.org/get&amp;#34;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  I&#39;ve formatted nested alists to use dot notation for better reading clarity. In other words changed &lt;code&gt;(a (b . c) (d . e))&lt;/code&gt; into &lt;code&gt;(a . ((b . c) (d . e)))&lt;/code&gt; which are the same thing.
&lt;/div&gt;
&lt;p&gt;The client made an HTTP request from the Fennel side and passed the response back to Emacs.
The response body was in JSON, but specifying &lt;code&gt;((:as . :json))&lt;/code&gt; as options map forced parsing the response body into Fennel tables.
Which, upon arriving in Emacs Lisp were converted into association lists.&lt;/p&gt;
&lt;p&gt;So now we can call Fennel from Elisp.
But why stop there?
Let&amp;rsquo;s call Emacs Lisp from Fennel!&lt;/p&gt;
&lt;h2 id=&#34;running-elisp-from-fennel-dot-dot&#34;&gt;Running ELisp from Fennel?..&lt;/h2&gt;
&lt;p&gt;Since this package uses the &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/&#34;&gt;Fennel Proto REPL&lt;/a&gt;, which is a custom protocol that can be extended at runtime, we can create a set of functions that will allow us to call back to Elisp.
Here&amp;rsquo;s how we extend the protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-elisp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.___repl___.pp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.env-set!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:emacs&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:call&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.id&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require-fennel/call&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:arguments&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-elisp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))}]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.receive&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;)))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setmetatable &lt;/span&gt;{}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:var&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.id&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require-fennel/var&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:var&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;}]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.receive&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setmetatable &lt;/span&gt;{}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.id&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require-fennel/eval&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:expr&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;}]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.receive&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt;))})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1000 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I had to update the protocol core a bit, adding the &lt;code&gt;protocol.env-set!&lt;/code&gt; and &lt;code&gt;protocol.receive&lt;/code&gt; functions.
The &lt;code&gt;env-set!&lt;/code&gt; allows us to create user-visible definitions.
So we add the &lt;code&gt;emacs&lt;/code&gt; table that holds three fields.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;call&lt;/code&gt; field is a table with some metatable trickery.
Since it&amp;rsquo;s an empty table, any key would trigger the &lt;code&gt;__index&lt;/code&gt; metamethod.
This metamethod can be another table or a function - in our case, it is the latter.
This function returns a handler that calls into &lt;code&gt;protocol.message&lt;/code&gt; that sends a custom OP &lt;code&gt;require-fennel/call&lt;/code&gt; that we can handle in our package.&lt;/p&gt;
&lt;p&gt;The same goes for the &lt;code&gt;var&lt;/code&gt; field, except it doesn&amp;rsquo;t return a function, it just returns a value.&lt;/p&gt;
&lt;p&gt;The last field, &lt;code&gt;eval&lt;/code&gt;, is a combination of both, kinda.
It is a function, not a table, and it accepts one argument - an expression to evaluate in Emacs.&lt;/p&gt;
&lt;p&gt;However, we can&amp;rsquo;t use these just yet.
The second part of the trick comes from the new ability to extend the main protocol handler with custom handlers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defgeneric&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_op&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Handler for a custom protocol OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The first argument OP is used for dispatching.  Accepts the whole
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;MESSAGE, and its CALLBACKS.  The default implementation of unknown OP is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;a nop.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this generic function, we can define new handlers in separate packages.
These are the methods I&amp;rsquo;ve added in &lt;code&gt;require-fennel.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:require-fennel/call&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Custom handler for the require-fennel/call OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Accepts a MESSAGE and its CALLBACKS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The MESSAGE contains a function to evaluate and its arguments.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :data %s}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:fun&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:arguments&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:require-fennel/var&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Custom handler for the require-fennel/var OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Accepts a MESSAGE and its CALLBACKS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The MESSAGE contains a var which value is then returned to Fennel.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :data %s}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel--elisp-to-fennel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:var&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cl-defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-handle-custom-op&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eql&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:require-fennel/eval&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Custom handler for the require-fennel/var OP.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Accepts a MESSAGE and its CALLBACKS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The MESSAGE contains an expression which is evaluated and its result is returned to Fennel.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :data %s}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-fennel--elisp-to-fennel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:expr&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These three fields and methods allow us to do anything with Emacs, and it happens in the same process, so we can access the full Emacs state.
For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Welcome to Fennel Proto REPL 0.6.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel version: 1.5.1-dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua version: PUC Lua 5.4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs.call.emacs-uptime&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;19 minutes, 17 seconds&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs.var.emacs-version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;31.0.50&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs.eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(with-current-buffer \&amp;#34; *fennel-elisp*\&amp;#34; (buffer-substring-no-properties (point-min) (point-max)))&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;; Welcome to Fennel Proto REPL 0.6.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;;; Fennel version: 1.5.1-dev
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;;; Lua version: PUC Lua 5.4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; (emacs.call.emacs-uptime)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;19 minutes, 17 seconds\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; emacs.var.emacs-version
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;31.0.50\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; (emacs.eval \&amp;#34;(with-current-buffer \\\&amp;#34; *fennel-elisp*\\\&amp;#34; (buffer-substring-no-properties (point-min) (point-max)))\&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Crazy!&lt;/p&gt;
&lt;h2 id=&#34;fennelmacs&#34;&gt;Fennelmacs&lt;/h2&gt;
&lt;p&gt;So now we can write Fennel scripts that can obtain data from Emacs, process it, and pass back the results.
Thus, our goal is achieved - we&amp;rsquo;ve added a second language to Emacs!&lt;/p&gt;
&lt;p&gt;Of course, it&amp;rsquo;s not the same as what Guile Emacs does.
We&amp;rsquo;re still running code in a separate process, adding communication between the two via some protocol.
It&amp;rsquo;s a neat trick, nothing more.
Guile Emacs, if it ever becomes the thing, will be more powerful, as we would be able to leverage all these different languages in the same process, possibly sharing the memory, calling functions interchangeably, etc.
Some may even write Emacs packages in Brainfuck, who knows.&lt;/p&gt;
&lt;p&gt;Still, this is really cool, in my opinion, and shows the power of Emacs pretty well.
If you&amp;rsquo;re into Fennel, like me, I hope you&amp;rsquo;ll enjoy using this package as I enjoyed making it.
See you at &lt;a href=&#34;https://conf.fennel-lang.org/2024&#34; target=&#34;_blank&#34;&gt;Fennel Conf&lt;/a&gt;!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Extending Emacs with Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 20 Dec 2024 03:23:00 +0300</pubDate>
    </item><item>
      <title>Doing things blindly</title>
      <link>https://andreyor.st/posts/2024-12-10-doing-things-blindly/</link>
      <guid>https://andreyor.st/posts/2024-12-10-doing-things-blindly/</guid>
      <description>&lt;p&gt;During the course of my life, I was mainly doing things blindly.
Not that I&amp;rsquo;m actually blind, what I mean is that I didn&amp;rsquo;t study that much.
Instead, I always preferred to rediscover things by myself.
For the most part.&lt;/p&gt;
&lt;p&gt;When I was little, I didn&amp;rsquo;t have any particular hobbies.
My childhood mainly consisted of playing outside with friends, watching cartoons on TV, and playing various games on my PC.
I wasn&amp;rsquo;t good with sports, due to some health conditions, and did not participate in any of the activity clubs, like handicraft clubs, drawing clubs, etc.&lt;/p&gt;
&lt;p&gt;My parents tried though.
Once they suggested that I try joining a pottery class, but I couldn&amp;rsquo;t stay because I was allergic to the paint they used.
Well, I did go to the English club for maybe 8 years, but it wasn&amp;rsquo;t my choice, my parents thought that it would be beneficial if I learned a second language, that is widely used.
They were totally right, but I didn&amp;rsquo;t understand that up until I was twenty-ish or so.
Still glad they did.&lt;/p&gt;
&lt;p&gt;Going back to my childhood, things changed when I discovered Macromedia Flash.
I would consider drawing animations my first serious hobby.
However I never went to the arts school, and I just did things the way I did them.
I wasn&amp;rsquo;t very good at animating, though I did learn a lot by myself, and If needed I can animate.
If you&amp;rsquo;ve seen the games I made recently, I&amp;rsquo;d say that animation skills obtained when I was toying with Flash were beneficial to me today.&lt;/p&gt;
&lt;p&gt;Later I asked my parents and went to the arts school.
I was studying there for two years before going to the university, as I was hoping to become a professional animator.
That didn&amp;rsquo;t really work out, I was told that I was too old for them to accept me to the full program, so I took courses that would provide me with some kind of certificate that should be enough for some universities, or so I was told.
However, most universities in our country hold an entry contest, and you have to be able to draw pretty well to pass.
So I didn&amp;rsquo;t bother with that and never went to become an animator.&lt;/p&gt;
&lt;p&gt;Though, I think that&amp;rsquo;s good because after drawing small cartoons on my own for maybe 8 years straight I was kinda bored of animation.
The results weren&amp;rsquo;t so good, and a mere 20 seconds of animation usually took a whole day of work.
I was mainly doing frame-by-frame style animation, without much shortcuts, and at 24FPS so&amp;hellip;&lt;/p&gt;
&lt;p&gt;My second hobby was historical fencing.
Yes, I said I wasn&amp;rsquo;t good with sports, but it wasn&amp;rsquo;t an official club, so they didn&amp;rsquo;t have any strict requirements.
I just told the trainer that I can&amp;rsquo;t run for too long, and may need an extra break or three.
They were fine with pretty much anyone, as the club was dying.&lt;/p&gt;
&lt;p&gt;I did fencing for three years or so, and in my last year of high school, I decided to stop.
I was going to move to a different city anyway, so I couldn&amp;rsquo;t continue here, and I wasn&amp;rsquo;t sure that I wanted to continue there.
Again, the club didn&amp;rsquo;t teach us that much, as it was just a bunch of high schoolers swinging swords around.
The club did participate in some local tournaments though, but I don&amp;rsquo;t remember us winning any.
So my sword skills are something I developed mostly on my own, and I can&amp;rsquo;t say I&amp;rsquo;m that good.&lt;/p&gt;
&lt;p&gt;Right at the time when I dropped fencing, I picked up a guitar.
For the second time, though, as my parents tried to put me into the music school, as they noticed that I was able to hear some pitch.&lt;/p&gt;
&lt;p&gt;I went to music school for two months, but couldn&amp;rsquo;t continue, as I was basically going into three full-blown schools now.
The English club was serious, and I had to do a lot of homework for it.
The ordinary school had a lot of homework as well.
And now the music school that demanded hours of homework on top of that.
So we decided to stop.&lt;/p&gt;
&lt;p&gt;Also, I can&amp;rsquo;t sing.
It&amp;rsquo;s funny because I hear that I can&amp;rsquo;t hit a single note with my voice and people often think that I have no musical ear, but that&amp;rsquo;s not true.
I can tell when my guitar is out of tune, tune it by ear, I even can tune to E without a tuner, though I just memorized how the E string should sound, I don&amp;rsquo;t have perfect pitch.
My inability to sing simply comes from the fact that I don&amp;rsquo;t know how to control my voice.
It was a problem in the music school because teachers didn&amp;rsquo;t like the fact that when we were doing choirs I just pretended to sing by opening my mouth, as I was tired of them constantly yelling at me.
At solfeggio, when the teacher asked us to sing the note they&amp;rsquo;d played at the piano I couldn&amp;rsquo;t do that, and I couldn&amp;rsquo;t really explain to them why.
All I said was - I know it&amp;rsquo;s not the right note, I just can&amp;rsquo;t sing it.
They were disappointed, but I got by sometimes by finding that note on the keyboard from memory when they let me.&lt;/p&gt;
&lt;p&gt;When I was in the last year of high school I picked up guitar once more, but I didn&amp;rsquo;t go to the teacher.
Instead, I decided to learn it on my own.
So I did, by watching YouTube videos back in 2010.
After grasping most of the concepts I began to learn tabulatures, as they didn&amp;rsquo;t require any knowledge of music theory besides some basic stuff.
Like the signs for stops or articulation.&lt;/p&gt;
&lt;p&gt;Now, here comes programming.
When I got to the university, the department I entered was &lt;em&gt;unique&lt;/em&gt;, if I may say so.
It was unfocused, there was little specialization, and the way they were teaching us was&amp;hellip; not great.
After five years, I can&amp;rsquo;t say that I knew how to do anything.
I wasn&amp;rsquo;t a bad student, I attended all the classes.
Still, after graduating, I wasn&amp;rsquo;t sure what kind of job I should get.&lt;/p&gt;
&lt;p&gt;Linux became another hobby for me.
I have been using Linux as my main OS since 2008 or so.
So naturally, I thought that I could find a job as a Linux administrator or something like that.
After going to several interviews it was obvious that I knew nothing about it either.&lt;/p&gt;
&lt;p&gt;Somehow I managed to find a job as a C programmer.
We had a whole semester of C++ at the university - surely it&amp;rsquo;s enough to learn C++, right?
What were they thinking?&lt;/p&gt;
&lt;p&gt;Anyway, I started working as a C programmer, writing tests for microcontrollers and SOCs.
I wasn&amp;rsquo;t good at that for maybe two years, and then something happened.
First, I discovered Vim, and Vimscript took my interest for quite a while.
I started making plugins and enjoying programming for the first time.
Vimscript was nothing like C, and the only other languages I saw before were Delphi, taught to us at the university during the first year, and ActionScript 2 when I was tinkering with Macromedia Flash.&lt;/p&gt;
&lt;p&gt;Vimscript ignited my interest in programming in general, and I gradually became more and more proficient with C.
After four years I had a Senior title and decided to change my stack because C started to become tiring.
So I studied Clojure for about two months and became a junior Clojure developer in a different company.&lt;/p&gt;
&lt;p&gt;I think the fact that they weren&amp;rsquo;t really teaching us programming at the university affected me in a bad way because if they did, I would grow much faster than it took me.
A lot of my friends from school started working when they were in their third year of the university, while I started another three years after them.
By accident, even.&lt;/p&gt;
&lt;p&gt;After that, I did a lot of experiments with other languages and expanded my knowledge, and now I feel pretty confident in my skills, but I still think that I could have learned most of the stuff at the university if the program had been better.
The program was awful, really, trust me.&lt;/p&gt;
&lt;p&gt;Going back to guitar for a second, I could say that I played guitar for 14 years now, but I did drop about five years ago, and just picked it up again recently.
However, I didn&amp;rsquo;t improve much from what I could do, say, after three years of learning.
I&amp;rsquo;ve plateaued.&lt;/p&gt;
&lt;p&gt;I can feel it now because I felt it so many times.&lt;/p&gt;
&lt;p&gt;With animation.&lt;/p&gt;
&lt;p&gt;With fencing.&lt;/p&gt;
&lt;p&gt;With programming.&lt;/p&gt;
&lt;p&gt;And now with music.&lt;/p&gt;
&lt;p&gt;With animation, I did quit because it wasn&amp;rsquo;t getting anywhere.
If I did recognize that I&amp;rsquo;ve reached a plateau, and I won&amp;rsquo;t be able to improve unless I take it seriously and study, I would stay at that plateau for the rest of my life.
I was too young to understand this, so I just quit.&lt;/p&gt;
&lt;p&gt;With fencing, I quit not because I&amp;rsquo;ve reached a plateau, but for a different reason, however, if I were to continue it in the same way, as I were, it would end up like that.
I still train occasionally, and I know my limits, and that I&amp;rsquo;m not really improving.
Learning proper fencing is hard, and there&amp;rsquo;s a lot of theory that goes into it, but I never studied anything, so hence the result.&lt;/p&gt;
&lt;p&gt;With programming, I&amp;rsquo;ve reached a plateau after two years of working, I couldn&amp;rsquo;t improve my C knowledge just by doing tasks.
I was mindlessly hitting a wall most of the time.
Luckily for me, I&amp;rsquo;ve managed to gain interest in studying programming - I read a few books and did a few side projects, and it was enough to break from the plateau and rise.
I feel that I&amp;rsquo;m reaching another plateau, though, maybe this one is a different one, I still have to reflect on this.&lt;/p&gt;
&lt;p&gt;With guitar, I&amp;rsquo;ve plateaued because I only played tabs.
It&amp;rsquo;s a mere act of repeating what the sheet tells you.
Yes, some musicians do just that for a living, but they still have a lot more knowledge than I am.
Lately, I started studying music theory, bit by bit - reading some hints here, picking up some tricks there.
Once I have a bit more understanding, I might take some actual lessons.&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;m saying is - I did most of the stuff in my life without actually knowing what I was doing.
I still do, occasionally.
Sometimes it&amp;rsquo;s fun, sometimes it&amp;rsquo;s just a waste of time.
And time is not a resource to spare.
I&amp;rsquo;m in my thirties now, and I think it&amp;rsquo;s time to start taking things more seriously.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Doing things blindly&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 10 Dec 2024 23:45:00 +0300</pubDate>
    </item><item>
      <title>Extending JSON encoder with custom types</title>
      <link>https://andreyor.st/posts/2024-11-04-extending-json-encoder-with-custom-types/</link>
      <guid>https://andreyor.st/posts/2024-11-04-extending-json-encoder-with-custom-types/</guid>
      <description>&lt;p&gt;One thing I like about Lua is that it has a limited amount of built-in types and data structures.
There are no objects, just tables.
And if you need a custom behavior, a metatable can be attached to any table to extend it with custom methods that integrate with the rest of Lua runtime.&lt;/p&gt;
&lt;p&gt;However, this is both a blessing and a curse.
And unfortunately, Lua developers made a huge mistake by breaking this API&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; once already, in a minor release even.&lt;/p&gt;
&lt;p&gt;As you may noticed, &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; has a lot of stuff.
It has asynchronous Channels, and various Readers, which act like objects, but are still ordinary tables underneath.
And this is true for a lot of Lua projects, tables are flexible enough to implement many cool things, so people do.&lt;/p&gt;
&lt;p&gt;However, this poses an interesting problem - because objects are not a thing in Lua, and a set of default metamethods is quite limited, there&amp;rsquo;s no default way of extending objects with custom behavior.
In Java, you would specify what interfaces are required for an object to have, and it often means that if something doesn&amp;rsquo;t implement them, a wrapper object is needed.
In Clojure, we can get away with protocols and multimethods, but Lua has neither of those.
In Lua, and subsequently Fennel, we have to be creative, because even though we can add stuff through metatables, not every value can have one.&lt;/p&gt;
&lt;p&gt;While working on fnl-http, I added a basic JSON parser and encoder.
The parser part is quite simple, as JSON has a specification and a fixed amount of data types to worry about.
It&amp;rsquo;s not like &lt;a href=&#34;https://github.com/edn-format/edn&#34; target=&#34;_blank&#34;&gt;EDN&lt;/a&gt; or XML, for example, which are both extensible data notations that can represent pretty much anything.
In JSON you get only these data types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number&lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;Array&lt;/li&gt;
&lt;li&gt;Object&lt;/li&gt;
&lt;li&gt;Boolean&lt;/li&gt;
&lt;li&gt;Null&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only difference from Lua here is that &lt;code&gt;null&lt;/code&gt; is &lt;code&gt;nil&lt;/code&gt; and Lua doesn&amp;rsquo;t have arrays as a separate type.
So implementing a parser was easy, and everything pretty much maps to Lua data structures one-to-one.&lt;/p&gt;
&lt;p&gt;Implementing JSON encoder, however, was not as easy.
For basic data types, it is easy enough, but once we touch custom objects created with metatables things get messy.&lt;/p&gt;
&lt;p&gt;For example, let&amp;rsquo;s say we need a set data structure.
A set is similar to a table, except the values are the same as the keys.
But, we may want to distinguish them from ordinary tables, if, say, we&amp;rsquo;re making a library that has a set of functions for working with mathematical sets.
Like &lt;code&gt;intersection&lt;/code&gt;, &lt;code&gt;difference&lt;/code&gt;, etc.
Here&amp;rsquo;s a set constructor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__newindex&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, we create an empty table and set its metatable to a bunch of functions that close over the local &lt;code&gt;data&lt;/code&gt;.
This technique is quite common in Lua and is called &lt;a href=&#34;https://www.lua.org/pil/13.4.4.html&#34; target=&#34;_blank&#34;&gt;proxy tables&lt;/a&gt;.
By using the empty table as a base, we ensure that any table access triggers the &lt;code&gt;__index&lt;/code&gt; or &lt;code&gt;__newindex&lt;/code&gt; metamethod, depending on the action.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s a problem.
If we try to print such an object in the REPL, we don&amp;rsquo;t get any information about it, even though it has values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt;) 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Additionally to that, we have no means of iteration over this data structure, as the default &lt;code&gt;next&lt;/code&gt; function will just return &lt;code&gt;nil&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can fix this by adding a &lt;code&gt;__pairs&lt;/code&gt; metamethod:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__newindex&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] #(&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$2&lt;/span&gt;)))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, printing works, albeit in a bit strange way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Set&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few years ago, I &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;remade&lt;/a&gt; the pretty-printer for Fennel, and support for custom objects was a huge part of its design.
In short, we can fix our object textual representation by using the &lt;code&gt;__fennelview&lt;/code&gt; metamethod.&lt;/p&gt;
&lt;p&gt;Now, &lt;code&gt;__fennelview&lt;/code&gt; is fine and all, but it is not exactly meant for extending existing objects.
Of course, given a Lua library, that implements these proxy tables you can add support for Fennel, but it&amp;rsquo;s more of an ad-hoc solution.
So it&amp;rsquo;s meant for library authors to make the Fennel REPL experience more user-friendly, and make sure that the printed representation can be read back by Fennel.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s not always possible to add &lt;code&gt;__fennelview&lt;/code&gt; to existing objects.
For example, one common complaint in Lua is that arrays start from &lt;code&gt;1&lt;/code&gt; and not &lt;code&gt;0&lt;/code&gt;.
We can &amp;ldquo;fix&amp;rdquo; that by implementing our own Array type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__newindex&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__len&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$2&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right now, the object above prints like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s assume this came from the library, and we wish to print this differently, e.g. as &lt;code&gt;(Array 1 2 3)&lt;/code&gt; instead of &lt;code&gt;[1 2 3]&lt;/code&gt; to make sure that such arrays are read back as 0-based arrays, and not as ordinary Lua tables.
We can do that, but it is tricky because we don&amp;rsquo;t have any means of accessing the &lt;code&gt;data&lt;/code&gt; closure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pp-doc-example&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;       &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(Array &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, as you can see, we have to use &lt;code&gt;wrap&lt;/code&gt; on every &lt;code&gt;Array&lt;/code&gt;, because each instance comes with its own metatable, and setting it once wouldn&amp;rsquo;t work.
And if we try to read back the printed representation we&amp;rsquo;ll get the old representation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we can make another wrapper:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So you can see, how this is a bit problematic.&lt;/p&gt;
&lt;h2 id=&#34;custom-json-encoders&#34;&gt;Custom JSON encoders&lt;/h2&gt;
&lt;p&gt;Now, this was a bit of a tangent, so let&amp;rsquo;s get back to the main topic - JSON encoding.
Because I can&amp;rsquo;t ask everyone to do this kind of wrapping, I decided to implement a different way of extending the &lt;code&gt;json.encode&lt;/code&gt; function.
Thus, the library now features two more functions: &lt;code&gt;register-encoder&lt;/code&gt; and &lt;code&gt;unregister-encoder&lt;/code&gt;.
The second one is for fixing mistakes, and won&amp;rsquo;t probably be used too much.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s see how we can add support for custom types.
First, we need a function that will tell if the given object is an instance of something we want to encode:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A library may provide a custom predicate to check if the given object is of the same type, like &lt;code&gt;chan?&lt;/code&gt; for asynchronous channels.
However, it can&amp;rsquo;t be used as is, because to register an encoder, such a function needs to return a singleton, that can be compared with &lt;code&gt;=&lt;/code&gt;.
So we return &lt;code&gt;Array&lt;/code&gt; from our example function.&lt;/p&gt;
&lt;p&gt;Next, we can implement the encoder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode-array&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;) 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can register it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.register-encoder&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;object?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode-object&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first argument is the object itself, and the second one is a function to obtain the object&amp;rsquo;s type.
Internally, &lt;code&gt;register-encoder&lt;/code&gt; calls the &lt;code&gt;object?&lt;/code&gt; function on the first argument to provide a bit more flexibility, in case &lt;code&gt;object?&lt;/code&gt; returns different values for different objects or based on the object&amp;rsquo;s properties.
The third argument is a function that provides the encoding.
It accepts a callback to encode nested values as a second argument.&lt;/p&gt;
&lt;p&gt;With that, we can register the encoder and encode our array as JSON by calling &lt;code&gt;(json (Array 1 2 3))&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.register-encoder&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode-array&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Array&lt;/span&gt; 1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[1, 2, 3]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should provide enough flexibility to support any proxy-based objects.&lt;/p&gt;
&lt;h2 id=&#34;custom-decoders&#34;&gt;Custom decoders&lt;/h2&gt;
&lt;p&gt;I decided not to add custom decoder support to this library, yet.
JSON doesn&amp;rsquo;t have any custom types, so it doesn&amp;rsquo;t make sense to parse its values to anything but default Lua types.&lt;/p&gt;
&lt;p&gt;One could argue, that it would be nice to have a way to parse arrays to zero-based ones, given that we can convert zero-based arrays to JSON.
While true, I think this only adds unnecessary complexity to the parser.&lt;/p&gt;
&lt;p&gt;One reason, registering an encoder requires a singleton as type designator is to ensure that objects can&amp;rsquo;t be mixed up.
If it was allowed to register encoders via string types, it would be possible to register two &lt;code&gt;&amp;quot;Array&amp;quot;&lt;/code&gt; types, making ambiguous what encoder would be used or would require to change the name in case of conflict.&lt;/p&gt;
&lt;p&gt;JSON has a fixed amount of types, so registering a decoder for, say, Array, would mean that all arrays would be parsed to this custom type in all of the project parts.
Meaning, that if you use a different library, that also uses this JSON parser, and internally expects one-based arrays it will break.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m open to changing my mind on this, but for now, I feel that custom encoders are sufficient enough to make this library more usable.
As a part of this change, I&amp;rsquo;m moving this library out from the &lt;code&gt;fnl-http&lt;/code&gt; repo into its own library, making &lt;code&gt;fnl-http&lt;/code&gt; depend on it instead, making it possible for other projects to use this parser more easily.
You can find the code &lt;a href=&#34;https://gitlab.com/andreyorst/json.fnl&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and I hope this library will be useful!&lt;/p&gt;
&lt;h2 id=&#34;foontones&#34;&gt;Foontones&lt;/h2&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.lua.org/manual/5.3/manual.html#8.2&#34; target=&#34;_blank&#34;&gt;deprecation&lt;/a&gt; of &lt;code&gt;__ipairs&lt;/code&gt; metamethod in Lua 5.3 resulted in an inability to implement custom iteration over custom sequential data structures.
For example, the zero-indexed array example would benefit from &lt;code&gt;__ipairs&lt;/code&gt; because we could specify that the iteration starts from &lt;code&gt;0&lt;/code&gt;.
With the default &lt;code&gt;ipairs&lt;/code&gt; we would always miss the first value.
It&amp;rsquo;s not hard to fix manually, by overriding &lt;code&gt;ipairs&lt;/code&gt; with a custom function that checks for &lt;code&gt;__ipairs&lt;/code&gt; metamethod:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.ipairs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__ipairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ip&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ip&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ipairs*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tbl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, it&amp;rsquo;s not practical to intrude into Lua&amp;rsquo;s standard library in such a way.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Extending JSON encoder with custom types&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 04 Nov 2024 06:39:00 +0300</pubDate>
    </item><item>
      <title>Streaming and receiving chunked multipart data with fnl-http</title>
      <link>https://andreyor.st/posts/2024-11-02-streaming-and-receiving-chunked-multipart-data-with-fnl-http/</link>
      <guid>https://andreyor.st/posts/2024-11-02-streaming-and-receiving-chunked-multipart-data-with-fnl-http/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been absent for a while - you may have noticed that compared to the previous year, I posted a lot less this time.
There are two closely related reasons for that.
First, I felt burned out from programming.
Second, I finally picked up a guitar after five or more years and started recording again.
Thus, now I only do hobby programming when I feel passionate or challenged in an entertaining way.
This works for me, but I have less material to write about.&lt;/p&gt;
&lt;p&gt;One such passionate project for me this year is &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt;.
It&amp;rsquo;s an &lt;code&gt;HTTP/1.1&lt;/code&gt; client and server implementation for Fennel made using &lt;a href=&#34;https://w3.impa.br/~diego/software/luasocket/home.html&#34; target=&#34;_blank&#34;&gt;luasocket&lt;/a&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; - another library of mine.&lt;/p&gt;
&lt;p&gt;Last time I posted, I was mostly talking about &lt;a href=&#34;https://andreyor.st/posts/2024-08-15-fnl-http-testing-with-fennel-test/&#34;&gt;testing&lt;/a&gt;.
And I&amp;rsquo;m glad that I wrote all these tests, because the change I&amp;rsquo;m going to talk about this time broke a lot of them, and I was able to diagnose problems much quicker.
But the main changes are related to the post I made before that: &lt;a href=&#34;https://andreyor.st/posts/2024-08-01-fnl-http-improvements/&#34;&gt;fnl-http Improvements&lt;/a&gt;.
In that post, the most exciting things for me were chunked transfer encoding and support for multipart requests.
I&amp;rsquo;ve implemented support for reading chunked responses (the client already could send chunked requests) and moved onto implementing multipart requests.&lt;/p&gt;
&lt;h2 id=&#34;http-server&#34;&gt;HTTP Server&lt;/h2&gt;
&lt;p&gt;For some time, the implementation was sufficient enough, so I started working on an &lt;abbr title=&#34;Proof Of Concept&#34;&gt;POC&lt;/abbr&gt; asynchronous HTTP server.
The server is pretty much bare-bones right now, though it features everything you need to implement a proper one.
Here&amp;rsquo;s how it can be used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.server&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.json&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keep-alive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:application/json&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;server.start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 3000})]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:wait&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a rather simple echo server, that sends back the parsed request as JSON.
Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.fnl-http.client&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:method&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;131&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x561839afe390&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 131
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 13
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, of course, this won&amp;rsquo;t work as is, because not all Lua values can be encoded as JSON.
Such examples are functions, and custom objects, like Readers.
We can cheat, though, and encode it as a Fennel table and send it back as a string:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keep-alive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:application/json&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can try a POST request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hello HTTP&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:content #&amp;lt;Reader: 0x55eeb3016fc0&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :headers {:Content-Length \&amp;#34;10\&amp;#34; :Host \&amp;#34;localhost:3000\&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :length 10
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :method \&amp;#34;POST\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :path \&amp;#34;/\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :protocol-version {:major 1 :minor 1 :name \&amp;#34;HTTP\&amp;#34;}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;183&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55eeb3059470&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 183
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 20
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should give you an idea of how to implement a proper handler.&lt;/p&gt;
&lt;p&gt;The reason the content is a Reader is simple - we don&amp;rsquo;t want to process any more data than we need when parsing the request.
Once we obtain the HTTP-related data, such as headers, method, path, and version, we wrap the rest of the data in a Reader object, so the handler function can work on it later or even discard it.
In this particular case, it&amp;rsquo;s as simple as doing &lt;code&gt;(request.content:read (tonumber request.headers.Content-Length))&lt;/code&gt; but it may vary depending on what was sent, and what path the client used.
So I&amp;rsquo;m leaving this open.
Using a Reader enables asynchronous and lazy processing of the request&amp;rsquo;s body.&lt;/p&gt;
&lt;h3 id=&#34;multipart-requests&#34;&gt;Multipart requests&lt;/h3&gt;
&lt;p&gt;What&amp;rsquo;s interesting, however, is that there may be multiple bodies, if the request is a multipart one.
We can send a multipart request like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;)}]})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ideally, the server should be able to first process the &lt;code&gt;foo&lt;/code&gt; part, and then a &lt;code&gt;file&lt;/code&gt; part.
Additionally, a file can be really big, so we might want to avoid reading it fully into memory.
For example, the JSON module of &lt;code&gt;fnl-http&lt;/code&gt; can parse files without fully reading them into memory, as it is based around readers.&lt;/p&gt;
&lt;p&gt;The question, however, is how do we give this to a handler without reading the request in full first?
We don&amp;rsquo;t know how many parts there will be, and we might not know the sizes of each part.
Let&amp;rsquo;s look at how the handler encodes this request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;)}]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:headers {:Content-Type \&amp;#34;multipart/form-data; boundary=------------aaec41d0-1c75-4037-a039-91cc2b31584c\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;           :Host \&amp;#34;localhost:3000\&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :method \&amp;#34;POST\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :parts #&amp;lt;function: 0x55eeb28e79c0&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :path \&amp;#34;/\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; :protocol-version {:major 1 :minor 1 :name \&amp;#34;HTTP\&amp;#34;}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;256&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55eeb31df9e0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 256
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see, that there&amp;rsquo;s no &lt;code&gt;content&lt;/code&gt; field anymore.
Instead, there&amp;rsquo;s a &lt;code&gt;parts&lt;/code&gt; field, and it is a function.&lt;/p&gt;
&lt;p&gt;This function is a standard Lua iterator, that you can call until it returns &lt;code&gt;nil&lt;/code&gt; or plug it in any of the iteration forms.
Let&amp;rsquo;s change our handler to support both &lt;code&gt;content&lt;/code&gt; and &lt;code&gt;parts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.headers.Content-Length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.headers.Content-Length&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.headers.Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunked&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parts&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request.parts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parts&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part.content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s look at this a bit closer.
The &lt;code&gt;case&lt;/code&gt; has two branches - one for &lt;code&gt;content&lt;/code&gt; and one for &lt;code&gt;parts&lt;/code&gt;.
The &lt;code&gt;content&lt;/code&gt; branch is pretty straightforward - we replace request&amp;rsquo;s &lt;code&gt;content&lt;/code&gt; field value with the data obtained from Reader.
If there was a Content-Length header, we used it to determine how much to read.
If not, we (rather crudely) check if the chunked Transfer-Encoding was used, and read all of the data from the Reader.
We can do so, because chunked readers know when to stop, based on the final chunk header.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;parts&lt;/code&gt; branch is similar, except we have to go one level deeper, and it&amp;rsquo;s a bit simpler to work with the part&amp;rsquo;s contents.
First, the main function of &lt;code&gt;icollect&lt;/code&gt; is to produce a sequential table from the iterator values.
We do so by replacing the &lt;code&gt;content&lt;/code&gt; field of each &lt;code&gt;part&lt;/code&gt;.
The &lt;code&gt;content&lt;/code&gt; field is again a Reader, but it&amp;rsquo;s a sized reader, so we can almost always read it in full.
Even if content length was not specified, parts are separated by boundaries, so we always know when to stop.&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;part&lt;/code&gt; is a table of the following structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;N&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; optional field, if headers had a Content-Length specified&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;part name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;name of the uploaded file&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; alternatively :filename* can be present instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;part kind&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As much information is given to make working with parts easier.
And because parts are provided by an iterator, we don&amp;rsquo;t have to know in advance how many parts are coming.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s a caveat - we can&amp;rsquo;t obtain information about each part first, and process the contents later.
Moving to the next part consumes the request body until the next boundary is given, so we can&amp;rsquo;t reverse the Reader back to its content.
Thus, doing this won&amp;rsquo;t work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;all-parts&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parts&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;all-parts&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part.content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll have to either copy reader contents into another in-memory Reader, or process parts as they appear.&lt;/p&gt;
&lt;p&gt;Now, we can try our request again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;)}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;multipart/form-data; boundary=------------a03996f2-0d1c-4aa4-97f5-ac90b06cb6ea&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:3000&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:method&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:parts&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Disposition&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data; name=\&amp;#34;foo\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;11&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;8bit&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/plain; charset=UTF-8&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;value\&amp;#34;: \&amp;#34;JSON data\&amp;#34;}\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-data.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Disposition&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data; name=\&amp;#34;file\&amp;#34;; filename=\&amp;#34;some-data.json\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;binary&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/octet-stream&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Transfer-Encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunked&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;808&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;tcp-client&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55cf2d942450&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 808
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 13
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:trace-redirects&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the &lt;code&gt;foo&lt;/code&gt; part had &lt;code&gt;length&lt;/code&gt; of &lt;code&gt;12&lt;/code&gt;, and the &lt;code&gt;file&lt;/code&gt; part had a chunked transfer encoding.&lt;/p&gt;
&lt;p&gt;Before this post, there was no way of sending multipart with chunked encoding, so this is a pretty good change in my opinion.
Definitively expands the possibilities.
Still need to test this with some real HTTP servers, as I don&amp;rsquo;t see this feature used too often though.&lt;/p&gt;
&lt;h3 id=&#34;performance&#34;&gt;Performance&lt;/h3&gt;
&lt;p&gt;Now, let&amp;rsquo;s talk performance.
I used the &lt;a href=&#34;https://github.com/wg/wrk&#34; target=&#34;_blank&#34;&gt;wrk&lt;/a&gt; tool to measure the server&amp;rsquo;s RPS with a simple handler that does 50 millisecond delay on each request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:io.gitlab.andreyorst.async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.timeout&lt;/span&gt; 50))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt; 11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;handler&lt;/code&gt; function is always running in an asynchronous context, so we can use parking operations such as &lt;code&gt;&amp;lt;!&lt;/code&gt; inside of it.&lt;/p&gt;
&lt;p&gt;Running it with 12 threads and 400 connections for 30 seconds yields about 2k requests per second:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Running 30s test @ http://localhost:3000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  12 threads and 400 connections
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Thread Stats   Avg      Stdev     Max   +/- Stdev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Latency   146.42ms   94.13ms   2.00s    98.54%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Req/Sec   205.07     90.83   343.00     62.36%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  69835 requests in 30.09s, 8.00MB read
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Socket errors: connect 0, read 0, write 0, timeout 151
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Requests/sec:   2321.21
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Transfer/sec:    272.37KB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not bad for a single-threaded Lua runtime, I would say!&lt;/p&gt;
&lt;p&gt;Now, of course, this kind of benchmark is more synthetic than real, so don&amp;rsquo;t expect it to work as well as it says here in all cases.
With a more complex handler, that deals with routing, and data processing this number will go down.
Still, I&amp;rsquo;m pretty satisfied with these results.&lt;/p&gt;
&lt;p&gt;And CPU usage is quite low too.
When idling a single CPU core is sitting at about 5%, and during the benchmark, it rises to 70%.
Removing the asynchronous sleep, raises CPU usage to 100% (single core), peaking at 67MB of RAM and serving about 4k requests per second.
So with an asynchronous sleep, our server process is doing some actual sleeping, leaving some resources to the OS!&lt;/p&gt;
&lt;p&gt;And given how &lt;code&gt;async.fnl&lt;/code&gt; is &lt;a href=&#34;https://andreyor.st/posts/2023-08-02-asyncfnl-enchancements/#hooks--the-less-wrong-way&#34;&gt;implemented&lt;/a&gt;, we can actually replace &lt;code&gt;(async.&amp;lt;! (async.timeout 50))&lt;/code&gt; with a blocking loop, like &lt;code&gt;(for [i 1 1_000_000] nil)&lt;/code&gt; and still get around 400 RPS.
That&amp;rsquo;s a busy loop with one million iterations per handler invocation on each request.
So you shouldn&amp;rsquo;t worry too much when blocking the handler.&lt;/p&gt;
&lt;p&gt;Is it a good result?
You be the judge.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Streaming and receiving chunked multipart data with fnl-http&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 02 Nov 2024 04:46:00 +0300</pubDate>
    </item><item>
      <title>Lazy Sequences and Java Streams</title>
      <link>https://andreyor.st/posts/2024-10-16-lazy-sequences-and-java-streams/</link>
      <guid>https://andreyor.st/posts/2024-10-16-lazy-sequences-and-java-streams/</guid>
      <description>&lt;p&gt;When Clojure 1.12.0 was released in September, the release note had a lot of cool features, such as virtual threads, but one feature caught my eye in particular: support for Java &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html&#34; target=&#34;_blank&#34;&gt;Stream&lt;/a&gt;s and functional interface support.
That was just what I needed at work to port one of our internal libraries to Java, to make it easier to reuse from projects written in different JVM languages.
Little did I know that Java Streams suck.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;p&gt;We have a small library, that implements queues with lazy sequences.
It has both producer and consumer parts, so several projects can reuse the same library, one being a producer, and the other being a consumer.
Today we&amp;rsquo;re interested in the consumer part.&lt;/p&gt;
&lt;p&gt;One of the features this library has is that we can have several separate queues, and we can take items from all of them in a fixed order.
Each queue is sorted, so when we have multiple queues, we need to get elements in order and still in a lazy way.
Let&amp;rsquo;s look at some examples:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, I created two infinite sequences of sorted numbers, just as an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1 3 5 7 9 11 13 15 17 19)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(0 2 4 6 8 10 12 14 16 18)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s not that different from actual queues used in our library, as each sequence is potentially infinite and sorted.
What we need to get as a result is a single queue with items of both queues combined with retained ordering:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;lazy-seq-solution&#34;&gt;Lazy Seq solution&lt;/h3&gt;
&lt;p&gt;To achieve this we can implement a merge sort function that will produce a single queue from multiple queues:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;sort-by first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Note, that I&amp;rsquo;ve omitted some checks for things like empty sequences, and such for the sake of simplicity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short, it evaluates like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let&amp;rsquo;s say, we have &lt;code&gt;[(1 3 5 7...) (0 2 4 6...)]&lt;/code&gt; as an input;&lt;/li&gt;
&lt;li&gt;We sort it by the first element of each sequence: &lt;code&gt;[(0 2 4 6...) (1 3 5 7...)]&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;We take the first element from the first queue: &lt;code&gt;0&lt;/code&gt;, and &lt;code&gt;cons&lt;/code&gt; it to the recursive call to which we pass back all of the sequences, except we remove the first element from the first queue;
&lt;ul&gt;
&lt;li&gt;Since the function returns a lazy sequence the recursive call is effectively trampolined.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And we can see that it works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;10 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;queue2&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(0 1 2 3 4 5 6 7 8 9)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;20 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take-nth &lt;/span&gt;3 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (0 3 6 9 12 ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take-nth &lt;/span&gt;3 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;drop &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (1 4 7 10 13 ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take-nth &lt;/span&gt;3 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;drop &lt;/span&gt;2 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (2 5 8 11 14 ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;20 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;drop &lt;/span&gt;20 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;)))]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (1 3 5 7 9 11 13 15 17 19 20 21 22 23 24 25 26 27 28 29)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;  \_first_sequence_only_/  \___both_sequences_merged___/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, it won&amp;rsquo;t work if sequence items are in arbitrary order, but that&amp;rsquo;s not the case for our implementation.&lt;/p&gt;
&lt;h3 id=&#34;java-stream-solution&#34;&gt;Java Stream solution&lt;/h3&gt;
&lt;p&gt;Now, as I mentioned, I had to rewrite this library in Java, for it to be reused in other projects written in other JVM languages.
It is possible to use a Clojure library from, say, Scala, but it is quite tedious to do so.
We either have to AOT compile the library to a jar, and provide a bunch of methods via &lt;code&gt;genclass&lt;/code&gt;.
Alternatively, it&amp;rsquo;s possible to load Clojure, compile the sources, and use it this way, but it introduces way too many hoops to jump through, that rarely anyone would want to do so in our team.
And the library in question is small, about 400 LOC with documentation strings and comments, so rewriting it in Java wouldn&amp;rsquo;t be that hard.&lt;/p&gt;
&lt;p&gt;Or so I thought.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not a Java programmer, and I have very limited knowledge of Java.
Thankfully, Java is a simple language, unless you wrap everything in an unnecessary amount of classes, use abstract fabric builders, and so on.
This library, thankfully, required neither of those cursed patterns - it&amp;rsquo;s a single static class with no need for instancing, with a bunch of pure methods.&lt;/p&gt;
&lt;p&gt;So, knowing that Java has a Stream class, and looking at its interface I thought that I would be able to implement this library.
And in truth, it wasn&amp;rsquo;t a problem, until I got to the lazy merge sort part.
That&amp;rsquo;s when it started looking cursed.&lt;/p&gt;
&lt;p&gt;First of all, a Stream is not a data structure - you can&amp;rsquo;t work with it as if it were data, you have to use pipelines, and then either consume it or pass it around.
Moreover, most examples use streams as an intermediate transformation step and return a collection, or suggest passing in a transformer, instead of returning a stream, so I wonder where is this coming from:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Java APIs increasingly return Streams and are hard to consume because they do not implement interfaces that Clojure already supports, and hard to interop with because Clojure doesn’t directly implement Java functional interfaces.&lt;/p&gt;
&lt;p&gt;From Clojure 1.12.0 &lt;a href=&#34;https://clojure.org/news/2024/09/05/clojure-1-12-0#_2_10_streams_with_seq_into_reduce_and_transduce_support&#34; target=&#34;_blank&#34;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anyhow, I&amp;rsquo;ve created functions that return streams of items in the queue, much like the ones I showed above.
So it was time to implement the merge sort.
Let&amp;rsquo;s look at the skeleton of our function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;static&lt;/span&gt; Stream&amp;lt;Object&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mergeSortStreams&lt;/span&gt;(Stream&amp;lt;Object&amp;gt;[] streams) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Stream.generate(() -&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// implement merge sort somehow...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;	});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Stream.generate(Supplier)&lt;/code&gt; produces an infinite stream, generated by calling the supplier.
Basically, it&amp;rsquo;s what we need here, we can do our sorting inside the supplier.
However, there&amp;rsquo;s a problem - Streams are not data structures.
And there&amp;rsquo;s &lt;strong&gt;no way to take one element without consuming the stream&lt;/strong&gt;.
I mean, there&amp;rsquo;s &lt;code&gt;stream.findFirst()&lt;/code&gt; but if we look at the documentation for it, we&amp;rsquo;ll see that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Optional&amp;lt;T&amp;gt; findFirst()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Returns an &lt;code&gt;Optional&lt;/code&gt; describing the first element of this stream, or an empty &lt;code&gt;Optional&lt;/code&gt; if the stream is empty. If the stream has no encounter order, then any element may be returned.&lt;/p&gt;
&lt;p&gt;This is a &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps&#34; target=&#34;_blank&#34;&gt;short-circuiting terminal operation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Returns:
an &lt;code&gt;Optional&lt;/code&gt; describing the first element of this stream, or an empty &lt;code&gt;Optional&lt;/code&gt; if the stream is empty
Throws:
&lt;code&gt;NullPointerException&lt;/code&gt; - if the element selected is null&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What is a short-circuiting terminal operation you ask?
A terminal operation may traverse the stream to produce a result or a side effect.
A short-circuiting terminal operation does the same, but even if presented with an infinite stream, it can finish in a finite time.
And after the terminal operation is performed, the stream is considered consumed, and can no longer be used.&lt;/p&gt;
&lt;p&gt;But even if we could use &lt;code&gt;findFirst&lt;/code&gt; without closing the stream, it wouldn&amp;rsquo;t be useful to us, because remember - we need to take the first element from each stream and sort the streams themselves.
But &lt;code&gt;findFirst&lt;/code&gt; is a destructive operation, it removes the element from the stream.&lt;/p&gt;
&lt;p&gt;In Clojure, sequences are immutable - all we can do is construct a new sequence if we wish to add items or take its tail if we need fewer items.
Thus &lt;code&gt;first&lt;/code&gt; does nothing to the sequence in question, we can freely call it on any sequence, obtain an element, do stuff with it, and be done.
You can think of &lt;code&gt;first&lt;/code&gt; like of an iterator &lt;code&gt;peek&lt;/code&gt;, where you look at what the next element is in the iterator without advancing it.&lt;/p&gt;
&lt;p&gt;Thankfully, we can convert a &lt;code&gt;Stream&lt;/code&gt; to an &lt;code&gt;Iterator&lt;/code&gt;, with it staying lazy and potentially infinite.
Only, there&amp;rsquo;s no &lt;code&gt;peek&lt;/code&gt; method in the base &lt;code&gt;Iterator&lt;/code&gt; class in Java.
Oh well.&lt;/p&gt;
&lt;p&gt;Well, we can always implement our own wrapper for the &lt;code&gt;Iterator&lt;/code&gt; class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org.example&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;java.util.Iterator&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PeekingIterator&lt;/span&gt;&amp;lt;T&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;implements&lt;/span&gt; Iterator&amp;lt;T&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Iterator&amp;lt;T&amp;gt; iterator;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;boolean&lt;/span&gt; peeked = &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;private&lt;/span&gt; T peeked_item;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;PeekingIterator&lt;/span&gt;(Iterator&amp;lt;T&amp;gt; it) { iterator = it; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; T &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (peeked) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            peeked = &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            T tmp = peeked_item;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            peeked_item = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; tmp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; iterator.next();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hasNext&lt;/span&gt;() { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; iterator.hasNext(); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; T &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;peek&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!peeked &amp;amp;&amp;amp; iterator.hasNext()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            peeked = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            peeked_item = iterator.next();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; peeked_item;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, we could use a dependency, but due to circumstances, we have to keep the amount of dependencies as low as possible.
Now, we can get back and implement our merge sort:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;static&lt;/span&gt; Stream&amp;lt;Object&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mergeSortStreams&lt;/span&gt;(Stream&amp;lt;Object&amp;gt;[] streams) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	List&amp;lt;PeekingIterator&amp;lt;Object&amp;gt;&amp;gt; iterators = &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (Stream&amp;lt;Object&amp;gt; s : streams) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		iterators.add(&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; PeekingIterator&amp;lt;&amp;gt;(s.iterator()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Stream.generate(() -&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		iterators.sort(Comparator.comparingInt(a -&amp;gt; (Integer) a.peek()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; iterators.getFirst().next();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Testing it with Clojure examples from above reveals that it works as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;System.out.println(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		mergeSortStreams(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Stream[]{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(1, i -&amp;gt; i + 2),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(0, i -&amp;gt; i + 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				.limit(20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				.collect(Collectors.toList())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// =&amp;gt; [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;System.out.println(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		mergeSortStreams(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Stream[]{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(0, i -&amp;gt; i + 3),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(1, i -&amp;gt; i + 3),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(2, i -&amp;gt; i + 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				.limit(20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				.collect(Collectors.toList())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// =&amp;gt; [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;System.out.println(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		mergeSortStreams(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Stream[]{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(1, i -&amp;gt; i + 2),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						Stream.iterate(20, i -&amp;gt; i + 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				.limit(20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				.collect(Collectors.toList())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// =&amp;gt; [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Obviously, I&amp;rsquo;m omitting most of the things in the code here, but this should be enough to give you an idea of what I had to do.&lt;/p&gt;
&lt;h3 id=&#34;sequences-vs-streams&#34;&gt;Sequences vs Streams&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s compare our versions.&lt;/p&gt;
&lt;p&gt;Clojure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;sort-by first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;merge-sort-sequences&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequences&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A pretty straightforward way of doing this kind of operation, in my opinion.&lt;/p&gt;
&lt;p&gt;Java:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;static&lt;/span&gt; Stream&amp;lt;Object&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mergeSortStreams&lt;/span&gt;(Stream&amp;lt;Object&amp;gt;[] streams) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	List&amp;lt;PeekingIterator&amp;lt;Object&amp;gt;&amp;gt; iterators = &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (Stream&amp;lt;Object&amp;gt; s : streams) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		iterators.add(&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; PeekingIterator&amp;lt;&amp;gt;(s.iterator()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Stream.generate(() -&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		iterators.sort(Comparator.comparingInt(a -&amp;gt; (Integer) a.peek()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; iterators.getFirst().next();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The general idea is the same but the fact that we had to create a peeking iterator, and store it in an array is disturbing.
In Clojure, we manipulate lazy sequences as if they were ordinary data.
In Java, we don&amp;rsquo;t have any real data, so we have to make our own way of accessing it.
We have to create an intermediate array list to sort it when every item in the stream is generated.
The same happens in Clojure, of course when we call &lt;code&gt;sort-by&lt;/code&gt;, and this is possibly worse, as in Java we only create the array once, and sort it in place, and in Clojure, we create a new list every time.
JVM is good at collecting garbage though, and the rate at which this sequence is consumed is far greater than the time to clean up the garbage, but it is a thing to consider.
Java streams also don&amp;rsquo;t specify anything about the order and can be processed in parallel, so I&amp;rsquo;m not sure how my &lt;code&gt;PeekingIterator&lt;/code&gt; would behave.&lt;/p&gt;
&lt;p&gt;And all of that is simply because Java streams are a half-backed interface made in a rush, or at least it feels like that.
Yes, it supports data pipelines with its own implementation of &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, etc., however, it makes me appreciate Clojure even more because it has one implementation of &lt;code&gt;map&lt;/code&gt; that works across everything (also, it has transducers).
In a more complete version of this Java library, we have to map over streams, transform them into iterators just to do some stuff, that is not implemented for streams, transform iterators back into streams, and so forth.
The Clojure version is much more straightforward, and concise.&lt;/p&gt;
&lt;p&gt;In hindsight, I wish it was easier to use Clojure from other JVM languages.
It would save me the time it took to re-implement everything in Java for sure.&lt;/p&gt;
&lt;p&gt;In the end, I hooked the old Clojure implementation to use the Java version as a core and retained the interface by converting streams to sequences via &lt;code&gt;stream-seq!&lt;/code&gt;.
It passed all of the library tests, so I moved on.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Lazy Sequences and Java Streams&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 16 Oct 2024 16:48:00 +0300</pubDate>
    </item><item>
      <title>Interactive game development with LÖVE</title>
      <link>https://andreyor.st/posts/2024-09-08-interactive-game-development-with-love/</link>
      <guid>https://andreyor.st/posts/2024-09-08-interactive-game-development-with-love/</guid>
      <description>&lt;p&gt;This is a continuation of the &lt;a href=&#34;https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/&#34;&gt;previous post&lt;/a&gt; on game development with the LÖVE game engine.
I&amp;rsquo;m slowly appreciating the freedom it gives, compared to the TIC-80 experience.
One of such freedoms is the fact, that LÖVE is a well-behaving console application.&lt;/p&gt;
&lt;p&gt;When you launch TIC, it boots up into a console:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/tic.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;If you do so from a terminal emulator, you can see that the same console is there too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; TIC-80 tiny computer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; version 1.1.2837 Pro (be42d6f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; https://tic80.com (C) 2017-2024
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; hello! type help for help
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[tic80.com]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mtd.lua
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, writing in this prompt doesn&amp;rsquo;t do anything - it&amp;rsquo;s not sent back into TIC.
And unfortunately, there&amp;rsquo;s no way of reading from standard IN, because there&amp;rsquo;s no &lt;code&gt;io&lt;/code&gt; namespace provided.
One could, theoretically, fiddle with sockets, if it is even possible to load them into TIC, which I&amp;rsquo;m not so sure about.&lt;/p&gt;
&lt;p&gt;In LÖVE, however, you get full Lua experience and more!
As you may know, Lua&amp;rsquo;s &lt;code&gt;io.read()&lt;/code&gt; is blocking, and there&amp;rsquo;s no real way of making it non-blocking or checking the input buffer.
However, that&amp;rsquo;s not a problem for LÖVE, as it has threads!
So we can set up a separate thread that reads from the &lt;code&gt;stdin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why would we want that?
Well, you see, when it comes to Lua, I usually do my programming in Fennel, and Fennel has a decent &lt;abbr title=&#34;Read Eval Print Loop&#34;&gt;REPL&lt;/abbr&gt; for doing interactive development.
I love the idea of programming with a REPL, I do it a lot for my hobby projects, and at work with Clojure.
Interactive development makes iterations much faster, and, in my experience, minimizes the amount of bugs in the resulting program.
And we can leverage that during game development too.&lt;/p&gt;
&lt;h2 id=&#34;adding-the-repl&#34;&gt;Adding the REPL&lt;/h2&gt;
&lt;p&gt;The way we&amp;rsquo;re going to set this up is as follows:&lt;/p&gt;
&lt;p&gt;We create a new, asynchronous handler for the REPL, and spawn it on the main thread.
Then, we&amp;rsquo;re going to spawn another thread, that will listen on &lt;code&gt;stdin&lt;/code&gt;, and send everything it reads to the main thread.
Finally, once the main thread finishes the evaluation, it sends the data back to the IO thread for printing.
After that, I&amp;rsquo;m going to spice things up by using the Fennel Proto REPL package I made for Emacs for a better REPL experience.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the REPL code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:love.event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib.fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;..&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stdout&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.stderr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.event.push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event-type&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newChannel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.wrap &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;errtype&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:moduleName&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib.fennel&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib/repl.fnl&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.compile-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.newFileData&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newThread&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:start&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.handlers.eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simply requiring this file would start a REPL.
You may be confused, about how&amp;rsquo;s it going to work, the &lt;code&gt;while true&lt;/code&gt; may look especially concerning.&lt;/p&gt;
&lt;p&gt;When we require this file, the &lt;code&gt;...&lt;/code&gt; is bound to the module name, so the &lt;code&gt;case&lt;/code&gt; doesn&amp;rsquo;t match, as it expects two values an &lt;code&gt;event-type&lt;/code&gt; and the &lt;code&gt;channel&lt;/code&gt;.
Then we fall into the &lt;code&gt;let&lt;/code&gt; block, which defines the channel &lt;code&gt;chan&lt;/code&gt;, the REPL handler &lt;code&gt;repl&lt;/code&gt;, starts the REPL coroutine, which pushes the &lt;code&gt;:read&lt;/code&gt; message to the channel.
Finally, we load this file again, using &lt;code&gt;love.filesystem.read&lt;/code&gt;, compile it to Lua, and start a new thread with &lt;code&gt;:eval&lt;/code&gt; for the &lt;code&gt;event-type&lt;/code&gt;, and &lt;code&gt;chan&lt;/code&gt; for the &lt;code&gt;channel&lt;/code&gt;.
This makes &lt;code&gt;case&lt;/code&gt; match and starts the &lt;code&gt;while&lt;/code&gt; loop, whose sole purpose is to take values off the &lt;code&gt;channel&lt;/code&gt; and act accordingly.&lt;/p&gt;
&lt;p&gt;Finally, we set the &lt;code&gt;love.handlers.eval&lt;/code&gt; handler, matching our &lt;code&gt;:eval&lt;/code&gt; event type to call the &lt;code&gt;repl&lt;/code&gt; as a callback when the event occurs.
The event occurs only when we get the &lt;code&gt;:read&lt;/code&gt; message from the channel, then we use &lt;code&gt;read&lt;/code&gt; to get data from the &lt;code&gt;stdio&lt;/code&gt;, and we push it back to the &lt;code&gt;eval&lt;/code&gt; handler so the &lt;code&gt;repl&lt;/code&gt; callback can be called.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s pretty much it!
Now, let&amp;rsquo;s put it to the test!&lt;/p&gt;
&lt;h2 id=&#34;changing-code-at-runtime&#34;&gt;Changing code at runtime&lt;/h2&gt;
&lt;p&gt;Here, I have a simple player controller and a bunch of values that correspond to how the player behaves:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fall-vel&lt;/span&gt; 300)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jump-vel&lt;/span&gt; -300)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run-vel&lt;/span&gt; 200)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;player&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:color&lt;/span&gt; [0.3 0.7 0.3 1]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:xvel&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:yvel&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; 50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; 50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:flip?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; 16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; 24
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:idle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:extra-jump&lt;/span&gt; 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:draw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; omitted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:update&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xvel&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;yvel&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extra-jump&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flip?&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; omitted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     )})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can try and change the &lt;code&gt;run-vel&lt;/code&gt; and see if it is picked up by the game:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/repl-doesnt-work.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Seems it&amp;rsquo;s not.
Perhaps, we need to recompile the game module?&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/error.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Aw, snap!&lt;/p&gt;
&lt;p&gt;By recompiling the entire module, we undefined some variables, and the game crashed!
By the way, the reason changing the run speed value didn&amp;rsquo;t apply is that we were actually defining a completely new speed value, that is not part of the module we&amp;rsquo;re editing.
That&amp;rsquo;s a quirk of how Lua modules work and how Fennel REPL works.
So let&amp;rsquo;s fix this!&lt;/p&gt;
&lt;h3 id=&#34;modules-and-state&#34;&gt;Modules and state&lt;/h3&gt;
&lt;p&gt;While Lua has some lisp characteristics, it is understandably not an actual lisp.
So, unfortunately, we can&amp;rsquo;t expect the same level of interactivity from it.&lt;/p&gt;
&lt;p&gt;In Lua, a module is an ordinary table.
When you write Lua, you return the value at the bottom of the file, usually a table, or sometimes a function.
Any local variables, defined in that module are locals, stored as closures for the functions that reference them in the exported value.&lt;/p&gt;
&lt;p&gt;Because of that, there&amp;rsquo;s no such thing as &lt;em&gt;entering a module&lt;/em&gt; like in many other lisps.
The REPL has its own kind of module space, where all locals, defined in the REPL are stored.
The same goes for any code that we send to the REPL.
So, while we do have a REPL, we can&amp;rsquo;t enter a specific module and change it partially - the only way to do that is to recompile the module and put the updated version in the &lt;code&gt;package.loaded&lt;/code&gt; table.
Which we can do.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s another problem lurking around - state.
The video above shows that the error message was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./game.fnl:68: attempt to index upvalue &amp;#39;world&amp;#39; (a nil value)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we&amp;rsquo;ve recompiled the module, &lt;code&gt;world&lt;/code&gt; became &lt;code&gt;nil&lt;/code&gt;, why?
Well, because &lt;code&gt;world&lt;/code&gt; is defined as a &lt;code&gt;nil&lt;/code&gt;, and later set in the &lt;code&gt;love.load&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.load&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bump.newWorld&lt;/span&gt; 64))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wall.height&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;player.height&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, the &lt;code&gt;love.load&lt;/code&gt; runs only when the game starts, and hence after recompiling the module, &lt;code&gt;world&lt;/code&gt; becomes &lt;code&gt;nil&lt;/code&gt; again, and our game doesn&amp;rsquo;t really expect that.
The same would happen to any other state we&amp;rsquo;re setting up when the game loads.&lt;/p&gt;
&lt;p&gt;Unfortunately, Fennel doesn&amp;rsquo;t have a &lt;code&gt;defonce&lt;/code&gt; or anything like it.
The &lt;code&gt;defonce&lt;/code&gt; macro is available in many lisps, and its purpose is to ensure that when we&amp;rsquo;re redefining something in the REPL or re-evaluating the whole module/namespace/package (whatever you guys call it) the value doesn&amp;rsquo;t get redefined.
Fennel lacks this because there&amp;rsquo;s no way of doing this in Lua, because of how locals are stored (as closed variables).&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s a way around this, we can move the definitions to another module, and use &lt;code&gt;require&lt;/code&gt; to load them.
In Lua &lt;code&gt;require&lt;/code&gt; caches everything it loads, so when we run &lt;code&gt;require&lt;/code&gt; again, it doesn&amp;rsquo;t really do anything except get the value from the &lt;code&gt;package.loaded&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how we can define the &lt;code&gt;world&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bump&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib.bump&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bump.newWorld&lt;/span&gt; 64)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &lt;code&gt;state/world.fnl&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it.
Now, we can bring it to the main game module using &lt;code&gt;require&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:state.world&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way, when we recompile the module, we get the same &lt;code&gt;world&lt;/code&gt; as before, unless we were to recompile the &lt;code&gt;world&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;I moved most of the game state in such modules, and now we can use our REPL.&lt;/p&gt;
&lt;h2 id=&#34;using-the-repl&#34;&gt;Using the REPL&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s an example of tweaking the player&amp;rsquo;s motion speed again:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/repl-work.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sending the code to the REPL, instead of reloading the module, just because it&amp;rsquo;s a bit more convenient.
This way tweaking the game is much nicer and frictionless, although it doesn&amp;rsquo;t reach the same heights as that one video from &lt;a href=&#34;https://www.youtube.com/watch?v=EGqwXt90ZqA&#34; target=&#34;_blank&#34;&gt;Bret Victor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s me using a REPL to make an ad-hoc level editor:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-interactive-game-development-with-love/level-editor.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, there&amp;rsquo;s no way of using the REPL on Android, since there&amp;rsquo;s no way of running LÖVE from the same environment as Emacs, without installing X11 and running everything through Termux.
Probably doable, but I don&amp;rsquo;t want to go this route.
Android development is more backup route anyway, since I have access to my PC again.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Interactive game development with LÖVE&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 08 Sep 2024 21:00:00 +0300</pubDate>
    </item><item>
      <title>Boredom and gamedev</title>
      <link>https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/</link>
      <guid>https://andreyor.st/posts/2024-09-08-boredom-and-gamedev/</guid>
      <description>&lt;p&gt;I spent the previous ten days on vacation.
Usually, I try to go off once or twice a year to somewhere where I can just passively relax - usually, it is some sea resort.
This year I decided to go to the Republic of Türkiye and spend my time at the beach without any major attractions.
The problem is - I get bored pretty quickly and my brain wants to do something.&lt;/p&gt;
&lt;p&gt;I took with me my trusty Nintendo 2DS in case I have an urge to spend some time looking at the screen and to get myself occupied on the plane, and a phone with some books to read while I&amp;rsquo;m lying on the beach.
However, my phone is also my computer, and I do a lot of coding on it in my spare time, usually when I don&amp;rsquo;t have access to a proper PC.&lt;/p&gt;
&lt;p&gt;The last time I went on such a vacation I got so bored, that I decided that I wanted to do some game dev, and started a &lt;a href=&#34;https://andreyor.st/posts/2023-06-09-gamedev-plans/&#34;&gt;personal game dev marathon&lt;/a&gt;.
Originally, I planned to start once I got back from vacation, but I was so eager that I &lt;a href=&#34;https://andreyor.st/posts/2023-06-30-game1/&#34;&gt;started early&lt;/a&gt;, while I was still at the beach.
The marathon was a crunch, and I had mixed feelings about it in the end, which ultimately led to burnout, and I put the idea of making games on the shelf for a while.
And while the last time I started doing this I only drew some sprites, the only reason for that was that I couldn&amp;rsquo;t get any game engine on my phone.
This time around, I got so bored that I started programming a game while gradually getting sunburns and taking breaks to go and actually swim in the sea.&lt;/p&gt;
&lt;h2 id=&#34;making-games-on-android&#34;&gt;Making games on Android&lt;/h2&gt;
&lt;p&gt;Basically, if the only thing you have is a phone you have two main options - &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt; and &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;löve2d&lt;/a&gt;.
tic has everything you need - an integrated code editor, a sprite editor, a map editor, and even a sound editor if you&amp;rsquo;re that versatile.
however, the experience of using TIC for doing everything is not great, especially on the phone.
I mean, that&amp;rsquo;s what you have to deal with:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/TIC-80.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Not a lot of screen space to view the code, the keyboard is abysmal, and the editor experience itself has a lot to be desired.
Yes, it is authentic, I get it, it&amp;rsquo;s just not what I&amp;rsquo;m personally after.&lt;/p&gt;
&lt;p&gt;On PC you can actually get a PRO version of TIC-80, which allows you to write a game in an external editor, and load it into the engine.
Technically, you could do the same on Android, but there&amp;rsquo;s a problem - I use Android 14, which has storage restrictions for apps.
And TIC-80 can&amp;rsquo;t access anything except files in its directory stored at &lt;code&gt;/sdcard/Android/data/com.nesbox.tic80/&lt;/code&gt;.
Which can&amp;rsquo;t be accessed directly on the phone either - you need a PC to access it.
So even if you have a separate text editor, you can&amp;rsquo;t do your game development with TIC on Android.
Moreover, you can&amp;rsquo;t even get your game out of the engine unless you have a PC at hand.&lt;/p&gt;
&lt;p&gt;The other option, as I said, is LÖVE2D.
It has the same problem as TIC, as you can&amp;rsquo;t launch the game from anywhere but &lt;code&gt;/sdcard/Android/data/org.love2d.android/&lt;/code&gt;, however, newer versions have a separate dedicated launcher, that can load &lt;code&gt;.love&lt;/code&gt; files from anywhere on the filesystem, which is good enough.
Alternatively, an older version, like 11.3 can be installed that bypasses the sandboxing restrictions.
So that was the route I took.&lt;/p&gt;
&lt;h3 id=&#34;making-games-on-android-with-löve&#34;&gt;Making games on Android with LÖVE&lt;/h3&gt;
&lt;p&gt;I have little experience with LÖVE2D.
Previously, I did a bunch of tests with it and made a few demos like the one described in my &lt;a href=&#34;https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/&#34;&gt;raymarching post&lt;/a&gt;, or the &lt;a href=&#34;https://gitlab.com/andreyorst/love-fabrik&#34; target=&#34;_blank&#34;&gt;F.A.B.R.I.K.&lt;/a&gt; algorithm I implemented back in the day.
So nothing major.
The raymarching demo barely runs on a PC, and there&amp;rsquo;s no way to control it on the phone without connecting a gamepad.
Unfortunately, I had no gamepad with me this time, so if I wanted to make a game on the phone I had to implement one myself.
Fortunately, I have a lot of experience playing games with the on-screen gamepad, so I&amp;rsquo;m at least well accustomed to the idea.&lt;/p&gt;
&lt;p&gt;I had no idea how to interact with the touch screen though, so I found a drop-in gamepad implementation for LÖVE2D in the &lt;a href=&#34;https://github.com/DeybisMelendez/game-tools/blob/90690b864e3d3b0ffeec66d04c1956198e383abf/lovepad.lua&#34; target=&#34;_blank&#34;&gt;game-tools repository&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/lovepad.png&#34;
         alt=&#34;Figure 1: lovepad.lua&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;&lt;code&gt;lovepad.lua&lt;/code&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Still, I wanted this gamepad to be a bit more advanced, with analog stick imitation, and more buttons, so I ported it to Fennel first and then extended it with more features:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;uninvertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/gamepad.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/gamepad.png&#34; title=&#34;Your browser does not support the &lt;video&gt; tag&#34;/&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It has all of the buttons of a modern controller, so I could share the control scheme between the on-screen gamepad and a real gamepad.
I do understand that the on-screen gamepad should, ideally, be tailored around a game, but this will suffice for now.
It was fun to implement this too, and I found a small bug in the &lt;code&gt;lovepad.lua&lt;/code&gt; file, while I was porting it.&lt;/p&gt;
&lt;p&gt;Next, I added the &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt; library for basic physics (because I don&amp;rsquo;t want to deal with box2d yet), and made a simple player controller:&lt;/p&gt;
&lt;figure class=&#34;uninvertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/player-controller.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, I&amp;rsquo;m using Emacs on the phone, with the Google Keyboard set to PC QWERTY layout - a neat feature.
This is my phone setup for programming, and I&amp;rsquo;m actually using the same configuration as on my regular PC.&lt;/p&gt;
&lt;p&gt;After adding a &lt;a href=&#34;https://github.com/kikito/gamera&#34; target=&#34;_blank&#34;&gt;camera library&lt;/a&gt; from the author of &lt;code&gt;bump.lua&lt;/code&gt;, here&amp;rsquo;s what the player controller looks like at the moment:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;uninvertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/player-controller.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I want to tweak this player-controller a bit further, making it more fleshed out, but as you can see it already handles a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direction facing is tracked based on horizontal velocity&lt;/li&gt;
&lt;li&gt;Jumping
&lt;ul&gt;
&lt;li&gt;Holding the jump button longer increases the jump height&lt;/li&gt;
&lt;li&gt;Bumping against a ceiling resets the vertical velocity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Crouching and crawling
&lt;ul&gt;
&lt;li&gt;When crouched, the player&amp;rsquo;s height is reduced, and when crawling the width is increased&lt;/li&gt;
&lt;li&gt;When crawling into a narrow space, the player changes to the crouched state if no direction input is given.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The camera follows the player
&lt;ul&gt;
&lt;li&gt;Camera pans in the direction of movement, showing more of the upcoming level&lt;/li&gt;
&lt;li&gt;Vertical position only changes when the player is grounded, or when the vertical position is lower than the original camera position&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I still need to tweak various speed values and add more movement options like dashing, sliding, etc., but it already feels &lt;em&gt;gameish&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Writing a player controller was the most challenging thing before when I &lt;a href=&#34;https://andreyor.st/posts/2023-07-17-game1-w34/&#34;&gt;made the first demo game&lt;/a&gt; in the marathon.
I made this one similar to the previous one, as can be seen in &lt;a href=&#34;http://andreyor.st/posts/2023-07-22-game1-w34-again/%20&#34; target=&#34;_blank&#34;&gt;further GAME1 demos&lt;/a&gt;, but it&amp;rsquo;s a complete rewrite, as I wanted to make it differently this time.
We&amp;rsquo;ll see how it evolves over time.&lt;/p&gt;
&lt;h3 id=&#34;drawing&#34;&gt;Drawing&lt;/h3&gt;
&lt;p&gt;While I didn&amp;rsquo;t draw anything for this game, I have a few updates on how I approach drawing on the phone.
In short, I ditched the &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.PixelStudio&#34; target=&#34;_blank&#34;&gt;PixelStudio&lt;/a&gt; I&amp;rsquo;ve talked about in the &lt;a href=&#34;https://andreyor.st/posts/2023-06-30-game1/&#34;&gt;first post&lt;/a&gt; about GAME1 mainly because its UX doesn&amp;rsquo;t work for me personally.
It&amp;rsquo;s still a good app for pixel art, I just don&amp;rsquo;t like how it works, and it lacks some features I&amp;rsquo;d like to have.&lt;/p&gt;
&lt;p&gt;Fortunately, there exists a better option - &lt;a href=&#34;https://krita.org/en/&#34; target=&#34;_blank&#34;&gt;Krita&lt;/a&gt; which has a &lt;a href=&#34;https://play.google.com/store/apps/details?id=org.krita&amp;amp;hl=en_US&#34; target=&#34;_blank&#34;&gt;port for Android&lt;/a&gt; that doesn&amp;rsquo;t compromise any features, so you get a full Krita experience.
It&amp;rsquo;s probably better suited for Android tablets, but works well enough for me on the phone.
I&amp;rsquo;m slowly learning pixel art, and here&amp;rsquo;s a timelapse of me drawing a tree on my phone:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted width=&#34;50%&#34;&gt;&lt;source src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/krita.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the &lt;video&gt; tag&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I made a few mistakes when using various tools, as I was not well accustomed to Krita&amp;rsquo;s toolset back then.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the final result after a bit of refinement:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-09-08-boredom-and-gamedev/pixelart.png&#34; width=&#34;100%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This isn&amp;rsquo;t a drawing for the game I&amp;rsquo;m making, just a sketch, following the principles outlined in this &lt;a href=&#34;https://www.youtube.com/watch?v=uFnL5X_GrmE&#34; target=&#34;_blank&#34;&gt;amazing video&lt;/a&gt; by Brandon James Greer.
But one thing that makes a difference when making games for LÖVE2D and not for TIC-80 is the unrestricted palette.
It&amp;rsquo;s still better to restrict the palette when making pixel art, but using only 16 colors for the entirety of game graphics is too restrictive for me.
Especially right now.&lt;/p&gt;
&lt;p&gt;One thing I haven&amp;rsquo;t tried yet is animating.
PixelStudio had a decent animation pipeline, and it was possible to export the animation as a sprite-sheet.
Still need to experience this in Krita - I know it has animation capabilities, but I&amp;rsquo;m not sure if they&amp;rsquo;ll be comfortable to use on the phone or not.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll be making more pixel art for this game I&amp;rsquo;m making in the future, so I&amp;rsquo;ll post actual images once I have anything more to share!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Boredom and gamedev&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 08 Sep 2024 00:34:00 +0300</pubDate>
    </item><item>
      <title>fnl-http - testing with fennel-test</title>
      <link>https://andreyor.st/posts/2024-08-15-fnl-http-testing-with-fennel-test/</link>
      <guid>https://andreyor.st/posts/2024-08-15-fnl-http-testing-with-fennel-test/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt; is my current passion project - I spend a lot of free time tinkering with it, and the last week was spent on testing and fixing bugs.&lt;/p&gt;
&lt;p&gt;As you may know, I made a testing framework, called &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test&#34; target=&#34;_blank&#34;&gt;fennel-test&lt;/a&gt;, which has a dedicated test runner, and a set of macros for writing tests.
I use it in all of my projects, and oftentimes, some project requires more features that are currently available in the framework, so I extend it as needed.
I think it&amp;rsquo;s a great way of designing something - you use it, and enhance it as you encounter new needs.&lt;/p&gt;
&lt;p&gt;I want programming to be exciting, so I spent a lot of time making my test report nice to look at.
Here&amp;rsquo;s how the report looks by default:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test run at Tue Aug  6 23:20:41 2024, seed: 1722975641242
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(....)(......)(.)(.....)(.)(........)(...)(...)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The default reporter is called &lt;code&gt;dots&lt;/code&gt;.
Each test namespace is encoded with parentheses &lt;code&gt;()&lt;/code&gt;, each successful test is encoded as a dot &lt;code&gt;.&lt;/code&gt;, and failed tests are encoded as &lt;code&gt;F&lt;/code&gt;.
The runner randomizes the order of tests each time, so if we run it again, the result would be different:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test run at Tue Aug  6 23:24:10 2024, seed: 1722975850235
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(......)(........)(.)(...)(...)(....)(.....)(.)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this is all you get with a reporter like this.
If a test fails, information about the error is printed after all tests have finished, so you know what test did fail.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another inbuilt reporter, called &lt;code&gt;namespaces&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Test run at Tue Aug  6 23:27:33 2024, seed: 1722976053226
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.http-parser-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.client-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.json-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.httpbin-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.body-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.headers-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.readers-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test.url-test: PASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it prints each namespace that is currently being tested, followed by the namespace-wide status.
If a test fails, you again see its error message, but only after all tests have finished, which isn&amp;rsquo;t ideal because tests in the &lt;code&gt;fnl-http&lt;/code&gt; project take about two minutes to complete.&lt;/p&gt;
&lt;p&gt;Fortunately enough, you can create reporters in the &lt;code&gt;.fennel-test&lt;/code&gt; configuration file!&lt;/p&gt;
&lt;h2 id=&#34;reporters&#34;&gt;Reporters&lt;/h2&gt;
&lt;p&gt;A reporter is just a table with a set of functions.
Each one is called when the respecting stage of testing is being run.
The methods are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ns-start&lt;/code&gt; - called when entering a new test namespace.&lt;/p&gt;
&lt;p&gt;Used to print the information about the namespace, such as its name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ns-report&lt;/code&gt; - called when exiting a test namespace.&lt;/p&gt;
&lt;p&gt;Used to print the overall status of the namespace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;test-start&lt;/code&gt; - called when running a single test from a namespace.&lt;/p&gt;
&lt;p&gt;Used to print the information about the test, such as the test&amp;rsquo;s name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;test-report&lt;/code&gt; - called after the test is finished.&lt;/p&gt;
&lt;p&gt;Used to print the status of the test.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;stats-report&lt;/code&gt; - called after running all tests in all namespaces.&lt;/p&gt;
&lt;p&gt;Used to print overall statistics of tests - how many tests were executed, how many errors were encountered, were there any warnings, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was enough for me to implement other kind of reporters, like the one in the &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-test#custom-reporters&#34; target=&#34;_blank&#34;&gt;project&amp;rsquo;s readme&lt;/a&gt;.
However, I wanted a bit more for this project - first, I wanted the report to be fun to look at, and second, I wanted some statistics.
And third, actually, I noticed the need to skip tests in case something is not available on the machine.&lt;/p&gt;
&lt;p&gt;After a bit of work, here&amp;rsquo;s what I&amp;rsquo;ve got:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-08-15-fnl-http-testing-with-fennel-test/new-reporter.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;With this reporter, if a specific test fails, I can immediately see it, without waiting for all tests to pass.
In the end, you can see some statistics on the longest tests, and average test time of the namespace.
For example, the &lt;code&gt;test.httpbin-test&lt;/code&gt; namespace took 90 seconds to complete, but on average each test only takes 11 seconds.
I&amp;rsquo;m not entirely sure why this metric would be necessary, but I&amp;rsquo;ve seen it in another test runner, so I implemented it in my reporter.&lt;/p&gt;
&lt;p&gt;Now, here&amp;rsquo;s a problem - one of the tests takes a whopping 90 seconds.
I don&amp;rsquo;t want to run this test all the time, especially, when I&amp;rsquo;m fixing a bug found by some other test.
So I introduced a &lt;code&gt;skip-test&lt;/code&gt; function as a first step.&lt;/p&gt;
&lt;p&gt;Originally, this function had two modes - terminating and non-terminating, but I later removed the second mode.
The reason for that is the &lt;code&gt;with-open&lt;/code&gt; macro.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of one of the fixtures I use in the &lt;code&gt;fnl-http&lt;/code&gt; project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;use-fixtures&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:once&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;podman run  -p &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:80 kennethreitz/httpbin &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; echo $!&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pid&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempts&lt;/span&gt; 10]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wait-for-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kill&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pid&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kill&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pid&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-test&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;coudln&amp;#39;t connect to httpbin server after &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempts&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; attempts&amp;#34;&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;with-open&lt;/code&gt; macro ensures that the resource is closed no matter what.
Closing the process, however, doesn&amp;rsquo;t kill the program running in the background, so I had to get its PID with sketchy &lt;code&gt;echo $!&lt;/code&gt; part and kill it later.
Killing the process doesn&amp;rsquo;t release the file descriptor created by &lt;code&gt;popen&lt;/code&gt;, so &lt;code&gt;with-open&lt;/code&gt; is only responsible for releasing the file handle here.&lt;/p&gt;
&lt;h3 id=&#34;a-sudden-bug&#34;&gt;A sudden bug&lt;/h3&gt;
&lt;p&gt;What &lt;code&gt;with-open&lt;/code&gt; also does is catching, and re-throwing errors.
It&amp;rsquo;s something akin to trying with resources in Java, and other languages that support this kind of abstraction.
You can think about it as &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;finally&lt;/code&gt; without the &lt;code&gt;catch&lt;/code&gt; part.&lt;/p&gt;
&lt;p&gt;Lua, however, doesn&amp;rsquo;t really have well-defined exceptions.
Instead, functions usually throw string messages about the error and that&amp;rsquo;s it.
Sometimes, however, it&amp;rsquo;s useful to throw a table instead.
Tables are like objects, so you can embed some additional information in those, making it easier to match a particular error.
It&amp;rsquo;s better to convert this table to a string if it ever reaches the user uncaught though.&lt;/p&gt;
&lt;p&gt;What makes things harder is that in Lua it&amp;rsquo;s not possible to re-throw an error without losing its previous stack trace.
While it is a common practice to use &lt;code&gt;pcall&lt;/code&gt; to catch any errors and to re-throw them if you can&amp;rsquo;t do anything about the error, this is what causes losing the precious stack trace.
More precisely, if the error message comes with the stack trace, and you would just re-throw it with &lt;code&gt;error&lt;/code&gt;, you wouldn&amp;rsquo;t add your stack trace to the trace.
Sounds convoluted, yeah?&lt;/p&gt;
&lt;p&gt;So Lua gives you another option: &lt;code&gt;xpcall&lt;/code&gt;.
The &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-xpcall&#34; target=&#34;_blank&#34;&gt;Lua manual&lt;/a&gt; doesn&amp;rsquo;t have a thorough explanation of it though:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;xpcall (f, msgh [, arg1, ···])&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This function is similar to &lt;code&gt;pcall&lt;/code&gt;, except that it sets a new message handler &lt;code&gt;msgh&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It works the same as &lt;code&gt;pcall&lt;/code&gt;, except, it accepts an additional argument - a function that would append a stack trace to the error.
Usually it&amp;rsquo;s the &lt;code&gt;debug.traceback&lt;/code&gt; &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-debug.traceback&#34; target=&#34;_blank&#34;&gt;function&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;debug.traceback ([thread,] [message [, level]])&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If message is present but is neither a string nor &lt;strong&gt;nil&lt;/strong&gt;, this function returns message without further processing.
Otherwise, it returns a string with a traceback of the call stack.
The optional message string is appended at the beginning of the traceback.
An optional &lt;code&gt;level&lt;/code&gt; number tells at which level to start the traceback (default is 1, the function calling &lt;code&gt;traceback&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Knowing all that, let&amp;rsquo;s look at how I&amp;rsquo;ve implemented the &lt;code&gt;skip-test&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Skip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__tostring&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Skip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Skip&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-test&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Calling this function inside a test or a fixture will stop the test
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;early and mark it as skipped. The optional `reason` argument is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;message to display in the log if the reporter is configured to do so.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Skip&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right, &lt;code&gt;skip-test&lt;/code&gt; throws an array with a special table object, defined as a singleton, so the test runner could distinguish between ordinary test errors and skipped tests.
In theory, everything should have worked, but for some reason, some of the tests were skipped correctly, but others didn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;The culprit?
It&amp;rsquo;s &lt;code&gt;with-open&lt;/code&gt;, obviously, otherwise, why would I take such a tangent about it?&lt;/p&gt;
&lt;p&gt;Internally, &lt;code&gt;with-open&lt;/code&gt; uses the &lt;code&gt;xpcall&lt;/code&gt; function to do its job.
And theoretically, it should work just fine, however, it doesn&amp;rsquo;t use &lt;code&gt;debug.traceback&lt;/code&gt; if Fennel&amp;rsquo;s own &lt;code&gt;compiler.traceback&lt;/code&gt; is available.&lt;/p&gt;
&lt;p&gt;Originally, I thought that&amp;rsquo;s just how it is, and implemented two modes in &lt;code&gt;skip-test&lt;/code&gt;.
After a bit of digging and consulting the manual, I found out that &lt;code&gt;compiler.traceback&lt;/code&gt; mistakenly converted &lt;strong&gt;every&lt;/strong&gt; message to a string.
&lt;a href=&#34;https://lists.sr.ht/~technomancy/fennel/patches/54416&#34; target=&#34;_blank&#34;&gt;Fixing that&lt;/a&gt; made the &lt;code&gt;skip-test&lt;/code&gt; function work in all cases.&lt;/p&gt;
&lt;h3 id=&#34;another-sudden-bug&#34;&gt;Another sudden bug!&lt;/h3&gt;
&lt;p&gt;After the patch landed, and I updated Fennel to the newest commit, something else broke.
Now, the JSON parsing test no longer succeeded, complaining that some number has no integer representation.
The number in question is &lt;code&gt;23456789012000000000000000000000000000000000000000000000000000000000000000000&lt;/code&gt; or, as it is written in the JSON test file that I use, &lt;code&gt;2.3456789012e+76&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before the update, everything worked fine, so I started digging again.
Turns out, recently, the way numbers are compiled by Fennel has changed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;font-weight:bold;display:flex;&#34;&gt;&lt;span&gt;@@ -534,8 +534,9 @@ (fn compile-sym
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;color:gray;display:flex;&#34;&gt;&lt;span&gt; ;; We do gsub transformation because some locales use , for
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;color:gray;display:flex;&#34;&gt;&lt;span&gt; ;; decimal separators, which will not be accepted by Lua.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;color:gray;display:flex;&#34;&gt;&lt;span&gt; (fn serialize-number [n]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-removed&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;-  (pick-values 1 (-&amp;gt; (tostring n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-removed&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;-                     (string.gsub &#34;,&#34; &#34;.&#34;))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;+  (if (= (math.floor n) n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;+      (string.format &#34;%d&#34; n)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;+      (string.gsub (tostring n) &#34;,&#34; &#34;.&#34;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now it is failing, because indeed, you can&amp;rsquo;t convert &lt;code&gt;2.3456789012e+76&lt;/code&gt; to a string using &lt;code&gt;%d&lt;/code&gt;.
Except, you can if you&amp;rsquo;re using LuaJIT - it happily converts this number to &lt;code&gt;&amp;quot;-9223372036854775808&amp;quot;&lt;/code&gt;, which is even worse.&lt;/p&gt;
&lt;p&gt;After a bit of searching, I found that the safest way to format &lt;strong&gt;integers&lt;/strong&gt; as stings is by using &lt;code&gt;&amp;quot;%.f&lt;/code&gt; format specifier.
Strangely enough, the Lua manual doesn&amp;rsquo;t have any information on most number formatting patterns.
A tiny bit of information was found on the lua-users.org &lt;a href=&#34;https://www.lua-users.org/wiki/IntegerDomain&#34; target=&#34;_blank&#34;&gt;page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To make sure integer numbers are properly converted into string (without scientific notation), rather than using &lt;code&gt;tostring(x)&lt;/code&gt;, use &lt;code&gt;format.string(&amp;quot;%.0f&amp;quot;,x)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t really get why &lt;code&gt;%.f&lt;/code&gt; would format a number as an integer given that &lt;code&gt;%f&lt;/code&gt; formats floats.
And, even though it works the same way in C, I have never seen this in my life.
But OK, we could just replace &lt;code&gt;%d&lt;/code&gt; with &lt;code&gt;%.f&lt;/code&gt;, and be done with that, however, the number above is then would appear as &lt;code&gt;&amp;quot;23456789012000000697746671432670411048021854502345623879537911769302235611136&amp;quot;&lt;/code&gt;.
I get it, it&amp;rsquo;s a big number, and Lua has limited precision for integers, but the main problem is that this number is much harder to read than its e-notation brother &lt;code&gt;2.3456789012e+76&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So I settled on finding a way to fix this bug so that both PUC Lua and LuaJIT would format this number in the same way.
The result is a &lt;a href=&#34;https://lists.sr.ht/~technomancy/fennel/patches/54443&#34; target=&#34;_blank&#34;&gt;patch&lt;/a&gt;, that changes the compiler and pretty-printer parts of the language.
The function that does that, looks horrifying:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;serialize-number&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.floor &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.f&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 99 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e%+?(%d+)$&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua stops transforming numbers from&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; e-notation to integers at e+14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt;) 14))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.gsub &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We start by checking if &lt;code&gt;(tostring n)&lt;/code&gt; and &lt;code&gt;(string.format &amp;quot;%.f&amp;quot; n)&lt;/code&gt; give the same string.
If they are, we just return the string.
If not, we try the scientific notation for each power from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;99&lt;/code&gt;.
I probably should&amp;rsquo;ve tested for more powers than that, but it&amp;rsquo;s OK for now.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re converting the number to a string using the e-notation and parse it back, comparing it with the original number.
What this does, is that if the power is less than the original, we would lose precision, and comparison would fail.
If we can&amp;rsquo;t find the exponent up to 99, we bail out and return the &lt;code&gt;%.f&lt;/code&gt; representation.
Otherwise, if the numbers match, we check if the exponent is greater than &lt;code&gt;14&lt;/code&gt; as it is the exponent where PUC Lua starts using the e-notation.
Otherwise, we again return the &lt;code&gt;%.f&lt;/code&gt; representation.&lt;/p&gt;
&lt;p&gt;Phew!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=aM8YOBvq-jc&#34; target=&#34;_blank&#34;&gt;But I&amp;rsquo;m not done yet!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try to compile a really huge number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; 1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e+99999&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s do it in an expression then, maybe that&amp;rsquo;s just the pretty printer freaking out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e+309&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;attempt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;perform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arithmetic&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;global &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;inf&lt;/span&gt;&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;del&gt;&lt;b&gt;What?&lt;/b&gt;&lt;/del&gt; I, of course, jest, but the reason this happens is pretty peculiar.&lt;/p&gt;
&lt;p&gt;You see - when we do &lt;code&gt;(tostring &amp;quot;%.f&amp;quot; n)&lt;/code&gt; on a huge number like &lt;code&gt;1e+309&lt;/code&gt; it returns the string &lt;code&gt;&amp;quot;inf&amp;quot;&lt;/code&gt;.
The compiler then happily includes it in the output Lua code, which is then run by the Lua VM.
In Lua, however, &lt;code&gt;inf&lt;/code&gt; is not a reserved identifier or a number, so it treats &lt;code&gt;inf&lt;/code&gt; like a variable name.
The &lt;code&gt;inf&lt;/code&gt; variable is unbound, hence the &lt;code&gt;nil&lt;/code&gt; in the first example, and an error in the second.&lt;/p&gt;
&lt;p&gt;So we need to account for that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;serialize-number&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.floor &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.f&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;inf&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(1/0)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; portable inf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-inf&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(-1/0)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; no precision loss&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 308 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; beyond 308 every number turns to inf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e%+?(%d+)$&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua keeps numbers in standard notation up to e+14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exp&lt;/span&gt;) 14))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;pick-values &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.gsub &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also brought the exponent limit up to the last number representable in this notation without becoming &lt;code&gt;inf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can go back to testing!&lt;/p&gt;
&lt;h2 id=&#34;counting-skipped-tests-and-assertions&#34;&gt;Counting skipped tests and assertions&lt;/h2&gt;
&lt;p&gt;The other thing I added to &lt;code&gt;fennel-test&lt;/code&gt; was more counters.
Counting skipped tests required some tinkering, like counting tests in the whole namespace if the tests were skipped from the &lt;code&gt;:once&lt;/code&gt; fixture.&lt;/p&gt;
&lt;p&gt;Counting assertions was even harder, because tests in &lt;code&gt;fennel-test&lt;/code&gt; are implemented through macros, and assertions are macros too.
I had to inject some runner state, conditionally, and modify it at runtime from each assertion.
A bit shady but it works.&lt;/p&gt;
&lt;p&gt;What is much more shady is the coverage reports for this project.&lt;/p&gt;
&lt;h2 id=&#34;coverage-report&#34;&gt;Coverage report&lt;/h2&gt;
&lt;p&gt;I have a firm belief that &lt;a href=&#34;https://andreyor.st/posts/2022-03-29-100-is-the-only-acceptable-test-coverage/&#34;&gt;100% is the only acceptable coverage&lt;/a&gt;.
However, and this is a big &lt;span style=&#34;font-size: 1.33em&#34;&gt;however&lt;/span&gt;, it&amp;rsquo;s important that such coverage comes from public API tests only.
Achieving 100% coverage this way means that your program doesn&amp;rsquo;t have any dead code and that your public API test at least touches all of our code at least once.
It doesn&amp;rsquo;t speak about test quality, of course, and it doesn&amp;rsquo;t guarantee that the program is bug-free, but those other points alone make a huge difference.&lt;/p&gt;
&lt;p&gt;Lua has one and only &lt;a href=&#34;https://lunarmodules.github.io/luacov/&#34; target=&#34;_blank&#34;&gt;luacov&lt;/a&gt; that you can use to test your code.
I&amp;rsquo;ve used it in some other Fennel projects in the past, but it comes with some nuances you have to deal with.&lt;/p&gt;
&lt;p&gt;First, luacov itself is imprecise.
In the post about 100% coverage I talk about it in more detail, but basically, I often see situations where the side effects happened, but the coverage report showed code responsible for the side effects as untouched.
Other times, the coverage percentage is bigger than its actual value due to code formatting.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;fnl-http&lt;/code&gt; project I hit a different problem.
Two, actually.&lt;/p&gt;
&lt;p&gt;The first one is related to the &lt;code&gt;--correlate&lt;/code&gt; option of the Fennel compiler.
I had an idea, that if I used &lt;code&gt;--correlate&lt;/code&gt; I could substitute Lua sources used to produce the coverage with Fennel sources.
And since the line numbers are matched by specifying the &lt;code&gt;--correlate&lt;/code&gt; option, the coverage report would be so much easier to read.&lt;/p&gt;
&lt;p&gt;Didn&amp;rsquo;t work out.&lt;/p&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;--coverage&lt;/code&gt; is imprecise.
Many parts of Fennel AST don&amp;rsquo;t contain any line information.
Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s the corresponding Lua code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; _local_1_ = require(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a = _local_1_[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; b = _local_1_[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- empty line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- empty line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {a = a, b = b}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- empty line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;As you can see, the overall amount of lines is the same, but many lines that are not empty in the Fennel example are empty in Lua.
It&amp;rsquo;s not a problem, as long as you&amp;rsquo;re measuring the coverage and viewing the report with Lua, but if we replace the Lua code with its Fennel counterpart, the report becomes invalid.
I guess, when the report is constructed, luacov checks if the line is empty or not, and if it isn&amp;rsquo;t, and there were no hits registered, it counts it as a miss.
I&amp;rsquo;m using &lt;code&gt;luacov-console&lt;/code&gt; to view the report, maybe it&amp;rsquo;s a bug from there, I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;The only way to fix this is to write the code accounting for these nuances of &lt;code&gt;--correlate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; local _local_1_ = require(&amp;#34;c&amp;#34;) local a = _local_1_[&amp;#34;a&amp;#34;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; local b = _local_1_[&amp;#34;b&amp;#34;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; &amp;lt;empty line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;}                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; return {a = a, b = b}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are more examples like that in the project&amp;rsquo;s code.&lt;/p&gt;
&lt;p&gt;The other problem is more peculiar.
Luacov uses &lt;code&gt;debug.sethook&lt;/code&gt; to build its report.
And I use the &lt;code&gt;async.fnl&lt;/code&gt; library in this project, which also uses &lt;code&gt;debug.sethook&lt;/code&gt; to schedule tasks.
So every time anything happens asynchronously, and trust me, there&amp;rsquo;s a lot of that in &lt;code&gt;fnl-http&lt;/code&gt;, the Luacov report is no longer properly calculated.&lt;/p&gt;
&lt;p&gt;So, Luacov has a lot of problems, but I understand why it is like that.
You can&amp;rsquo;t really instrument the Lua code in some other way.&lt;/p&gt;
&lt;p&gt;Fennel, on the other hand, isn&amp;rsquo;t like that.
Being a language where everything is an expression, we can probably make some compiler plugin that injects some side-effecting code that writes the report for every expression in the code.
It would be difficult to do with things like tables and destructuring, but it should be doable.
Maybe I&amp;rsquo;ll try to tackle this problem in the future, who knows?&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s all from me for now!
As usual, you can check out the &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;project&lt;/a&gt;, which contains all of the stuff mentioned above regarding &lt;code&gt;fennel-test&lt;/code&gt; and &lt;code&gt;luacov&lt;/code&gt;.
Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: fnl-http - testing with fennel-test&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 15 Aug 2024 23:01:00 +0300</pubDate>
    </item><item>
      <title>fnl-http Improvements</title>
      <link>https://andreyor.st/posts/2024-08-01-fnl-http-improvements/</link>
      <guid>https://andreyor.st/posts/2024-08-01-fnl-http-improvements/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/&#34;&gt;last post&lt;/a&gt; two weeks ago I described the process of making an asynchronous HTTP/1.1 client from scratch (minus the socket part).
At the end, I mentioned that there&amp;rsquo;s a lot more to implement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now, of course, that&amp;rsquo;s not all that needs to be implemented.
In its current state, this client doesn&amp;rsquo;t support responses that do not specify the Content-Length or produce a response body in chunked encoding.
HTTPS is out of the question for now too.
Most of the code just takes a &amp;ldquo;happy path&amp;rdquo; without much thought given to errors or more complicated scenarios.
But it&amp;rsquo;s fine, I can always make it better down the line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTPS is still out of the question - to be honest, I don&amp;rsquo;t want to deal with binary protocols that much, and get myself involved with implementing SSL in Lua.
I could, of course use a library, but I feel that Luasocket alone is already big enough dependency.&lt;/p&gt;
&lt;p&gt;So here are improvements so far.&lt;/p&gt;
&lt;h2 id=&#34;chunked-transfer-encoding&#34;&gt;Chunked transfer-encoding&lt;/h2&gt;
&lt;p&gt;As previously mentioned, the client didn&amp;rsquo;t understand chunked responses, so I had to fix it with a chunked body reader:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-chunk-size&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TODO: needs to process chunk extensions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s*([0-9a-fA-F]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tonumber &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0x&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;line missing chunk size: %q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunked-body-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initial-chunk&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Reads body in chunks, buffering each fully, and requesting the next
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;chunk, once the buffer is empty.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initial-chunk&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;more?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TODO: needs to process entity headers after the last chunk.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;more?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chunk-size&lt;/span&gt; 0) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)))))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a mess, but it works.
Please, refer to the &lt;a href=&#34;https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/#reader&#34;&gt;previous post&lt;/a&gt; for the explanation of what a reader is.&lt;/p&gt;
&lt;p&gt;The main idea here is that, when the chunked transfer encoding is detected, we create a reader with &lt;code&gt;chunked-body-reader&lt;/code&gt; instead of a regular &lt;code&gt;body-reader&lt;/code&gt;, and set up an internal string buffer.
We then process all reading operations in terms of this buffer, until it depletes, or when we request more data than left in the buffer.
After that, we download the next chunk.&lt;/p&gt;
&lt;p&gt;We still get a stream-like behavior out of this, although it has a somewhat big issue - if the server responds with a chunk of enormous size, we can fill up all available memory.
I&amp;rsquo;ve thought of reworking this function to fill the buffer with smaller chunks, but it complicates the code even further, so I decided not to.
For now, at least.&lt;/p&gt;
&lt;p&gt;And this now works both ways!
We can send a chunked body to the server if we&amp;rsquo;ve didn&amp;rsquo;t specify the &lt;code&gt;Content-Length&lt;/code&gt; header, and the body is not a string.
This happens automatically for files, other readers, and channels.
Yes, with this library, you can stream data to a server from a channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-file&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 300))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://some-server.org&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will stream the file line by line, sending each line every 300 milliseconds.
The server will receive each line as a separate chunk.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t go into much detail on how this is implemented, as I would need to go through &lt;strong&gt;a lot&lt;/strong&gt; of code.&lt;/p&gt;
&lt;h2 id=&#34;multipart-requests&#34;&gt;Multipart requests&lt;/h2&gt;
&lt;p&gt;After I finished with chunked requests, I turned my eyes on &lt;code&gt;multipart/form-data&lt;/code&gt;.
It&amp;rsquo;s an interesting part of HTTP, and after a closer look at it, I realized that email is just a multipart request with weird headers.
I&amp;rsquo;ve been editing emails in Emacs for quite some time but never noticed that the head of the mail is exactly like the head of an HTTP request.
&lt;em&gt;What a revelation!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That aside, implementing multipart came with a challenge.
I don&amp;rsquo;t know if it&amp;rsquo;s just me, but I couldn&amp;rsquo;t find anywhere if the total &lt;code&gt;Content-Length&lt;/code&gt; header is &lt;strong&gt;required&lt;/strong&gt; for a multipart request or not.
Logically speaking, since every part is separated by a boundary, a server should be able to read a request&amp;rsquo;s body until the final boundary.
So theoretically, it doesn&amp;rsquo;t have to know the total content length of the request.&lt;/p&gt;
&lt;p&gt;However, I&amp;rsquo;ve been testing my client with the &lt;a href=&#34;http://httpbin.org/&#34; target=&#34;_blank&#34;&gt;httpbin.org&lt;/a&gt; service and, for some reason, it doesn&amp;rsquo;t parse the multipart request unless the &lt;code&gt;Content-Length&lt;/code&gt; header is present.
And it&amp;rsquo;s not just the sum of part lengths, it&amp;rsquo;s also their headers, empty lines that separate the header part from content, and so forth.&lt;/p&gt;
&lt;p&gt;So I had to implement a set of functions to format multipart parts, and count their lengths:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-multipart-part&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mime-type&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Format a single multipart entry.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The part starts with the `boundary`, followed by headers, created from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`name`, optional `filename` or `filename*` for files, `mime-type`, and
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`content-length` which is either calculated from `content` or provided
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;explicitly.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Default headers include `content-disposition`, `content-length`,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`content-type`, and `content-transfer-encoding`. Provide `headers` for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;additional or to change the default ones.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--%s\r\n%s\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;collect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-disposition&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;form-data; name=%q%s%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;; filename=%q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;; filename*=%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;urlencode-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mime-type&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guess-content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-transfer-encoding&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guess-transfer-encoding&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function just formats a single multipart header, i.e. it doesn&amp;rsquo;t include the content.
The content is streamed later, so we don&amp;rsquo;t need it here.&lt;/p&gt;
&lt;p&gt;But with this function, we can now calculate the total length of our request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart-content-length&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Calculate the total length of `multipart` body.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Needs to know the `boundary`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;accumulate &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;total&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-multipart-part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;) 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;2 (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t determine length for multipart content %q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;missing length field on non-string multipart content %q&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) 2)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--%s--\r\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function doesn&amp;rsquo;t construct the whole body either - it only calculates the length based on headers, and the length of content fields that it can reasonably calculate.
There&amp;rsquo;s a small bug in the &lt;code&gt;format-multipart-part&lt;/code&gt; function though.
We can override any header, including &lt;code&gt;content-length&lt;/code&gt;, meaning we can break the request, if we send a string, and provide a different content-length for it either by mistake or deliberately.
This can be fixed, of course, by either not allowing to change content length for strings, or by wrapping string bodies in a string reader.
I&amp;rsquo;ll have to think about what method is better here.&lt;/p&gt;
&lt;p&gt;That aside, we can now stream the multipart request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream-multipart&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Write `multipart` entries to `dst` separated with the `boundary`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mime-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multipart&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Multipart content cannot be nil&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Multipart body must contain at least content and name&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wrap-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-multipart-part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream-body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content-length&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dst&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--%s--\r\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;boundary&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, I&amp;rsquo;m not going to dive too deep here.
If you&amp;rsquo;re interested in the code, you can find and read it &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of a multipart request body:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--a25537b6-51d6-491f-b18b-a33d197ae4c6\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;#34;json-test&amp;#34;; filename=&amp;#34;test.json&amp;#34;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 1438\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Transfer-Encoding: binary\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: application/octet-stream\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;#34;JSON Test Pattern pass1&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&amp;#34;object with 1 member&amp;#34;:[&amp;#34;array with 1 element&amp;#34;]},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    -42,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;integer&amp;#34;: 1234567890,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;real&amp;#34;: -9876.543210,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;e&amp;#34;: 0.123456789e-12,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;E&amp;#34;: 1.234567890E+34,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;&amp;#34;:  23456789012E66,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;zero&amp;#34;: 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;one&amp;#34;: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;space&amp;#34;: &amp;#34; &amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;quote&amp;#34;: &amp;#34;\&amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;backslash&amp;#34;: &amp;#34;\\&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;controls&amp;#34;: &amp;#34;\b\f\n\r\t&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;slash&amp;#34;: &amp;#34;/ &amp;amp; /&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;alpha&amp;#34;: &amp;#34;abcdefghijklmnopqrstuvwyz&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;ALPHA&amp;#34;: &amp;#34;ABCDEFGHIJKLMNOPQRSTUVWYZ&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;digit&amp;#34;: &amp;#34;0123456789&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;0123456789&amp;#34;: &amp;#34;digit&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;special&amp;#34;: &amp;#34;`1~!@#$%^&amp;amp;*()_+-={&amp;#39;:[,]}|;.&amp;lt;/&amp;gt;?&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;hex&amp;#34;: &amp;#34;\u0123\u4567\u89AB\uCDEF\uabcd\uef4A&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;true&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;false&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;null&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;array&amp;#34;:[  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;object&amp;#34;:{  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;address&amp;#34;: &amp;#34;50 St. James Street&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;url&amp;#34;: &amp;#34;http://www.JSON.org/&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;comment&amp;#34;: &amp;#34;// /* &amp;lt;!-- --&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;# -- --&amp;gt; */&amp;#34;: &amp;#34; &amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34; s p a c e d &amp;#34; :[1,2 , 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 , 5	   ,  		        6           ,7        ],&amp;#34;compact&amp;#34;:[1,2,3,4,5,6,7],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;jsontext&amp;#34;: &amp;#34;{\&amp;#34;object with 1 member\&amp;#34;:[\&amp;#34;array with 1 element\&amp;#34;]}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;quotes&amp;#34;: &amp;#34;&amp;amp;#34; \u0022 %22 0x22 034 &amp;amp;#x22;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;#34;/\\\&amp;#34;\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&amp;amp;*()_+-=[]{}|;:&amp;#39;,./&amp;lt;&amp;gt;?&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;: &amp;#34;A key can be any string&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    0.5 ,98.6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;99.44
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1066,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1e1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.1e1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1e-1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1e00,2e+00,2e-00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,&amp;#34;rosebud&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--a25537b6-51d6-491f-b18b-a33d197ae4c6\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Disposition: form-data; name=&amp;#34;description&amp;#34;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Length: 27\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Transfer-Encoding: 8bit\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/plain; charset=UTF-8\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a JSON file to test parsers\r
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--a25537b6-51d6-491f-b18b-a33d197ae4c6--\r
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s this request issued with the client library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.post&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/post&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multipart&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;json-test&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test/data/valid.json&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test.json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a JSON file to test parsers&amp;#34;&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:files&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json-test&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; contents were excluded to save some vertical space&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:form&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:description&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a JSON file to test parsers&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1946&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;multipart/form-data; boundary=------------5af9b616-6e9d-4c19-8aa5-cc0c5f52ca11&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:X-Amzn-Trace-Id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-66aad04d-5155e53a4023b5726bdd134e&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/post&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2118&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Thu, 01 Aug 2024 00:01:18 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;SocketChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x559596d0e200&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 2118
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 388
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the JSON got into the &lt;code&gt;files&lt;/code&gt; field, and the description into the &lt;code&gt;form&lt;/code&gt; field.&lt;/p&gt;
&lt;h2 id=&#34;redirects-and-query-params&#34;&gt;Redirects and query-params&lt;/h2&gt;
&lt;p&gt;Honestly, implementing redirection was a pain in the butt.
But I&amp;rsquo;m glad that I did!&lt;/p&gt;
&lt;p&gt;First, I now finally understand how redirection works.
Second, I had to do a major code refactoring for it, which made some parts more approachable, and robust.
That was a lot of changes, though.&lt;/p&gt;
&lt;p&gt;Alongside redirects, I improved the URL parser and implemented a query builder, that can merge multiple queries into one.
Here&amp;rsquo;s an example, again with httpbin.org:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/redirect-to?status_code=302&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:query-params&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:X-Amzn-Trace-Id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-66aad21a-4c52d9316b88f5d862a4b535&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;199&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Thu, 01 Aug 2024 00:08:58 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;SocketChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x559596734da0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 199
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 394
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the query params in the URL string and the &lt;code&gt;query-params&lt;/code&gt; field in the options table were merged.
During the merge, all values are URL-encoded, so you can pass in URLs that are not entirely correct, and it should work.&lt;/p&gt;
&lt;p&gt;Of course, we can change how we deal with redirects, limiting the total amounts of redirects:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/absolute-redirect/4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:max-redirects&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;too&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;many&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;redirecs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, we can choose not to follow redirects altogether:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/absolute-redirect/4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:follow-redirects?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE HTML PUBLIC \&amp;#34;-//W3C//DTD HTML 3.2 Final//EN\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;title&amp;gt;Redirecting...&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;h1&amp;gt;Redirecting...&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;You should be redirected automatically to target URL: &amp;lt;a href=\&amp;#34;http://httpbin.org/absolute-redirect/3\&amp;#34;&amp;gt;http://httpbin.org/absolute-redirect/3&amp;lt;/a&amp;gt;.  If not click the link.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;283&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html; charset=utf-8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Thu, 01 Aug 2024 00:24:48 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Location&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/absolute-redirect/3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-client&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;SocketChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x5589fcb69530&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:length&lt;/span&gt; 283
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;FOUND&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:request-time&lt;/span&gt; 228
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 302}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;changes-in-the-asynchronous-api&#34;&gt;Changes in the asynchronous API&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve decided to make it easier for users of this library to work with the client&amp;rsquo;s asynchronous API, and you should no longer be required to use &lt;code&gt;async.fnl&lt;/code&gt; directly.
Instead, every request function now accepts callbacks for processing responses, and exceptions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://lua-users.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;on-raise&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err.status&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means, that the only need for &lt;code&gt;async.fnl&lt;/code&gt; is if you need to wait for certain requests to complete.
It also means, that the &lt;code&gt;http.METHOD&lt;/code&gt; functions will no longer return a promise channel, as I promised in the previous post.&lt;/p&gt;
&lt;p&gt;In addition to that, it is now possible to read the response body, returned as a stream on the main thread, even if the request was asynchronous.
This is possible because I&amp;rsquo;ve cheated:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Takes a value from `port`.  Will return `nil` if closed.  Will block,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;if nothing is available and used on the main thread.  Will park if
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;used in the `(go ...)` block.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Puts a `val` into `port`.  `nil` values are not allowed.  Will block,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;if no buffer space or consumer are available and used on the main
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;thread.  Will park if used inside a `(go ...)` block.  Returns `true`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;unless `port` is already closed.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now try to do something like that in Clojure!
You can read why this works in my post on &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;async.fnl&lt;/a&gt;, or watch my &lt;a href=&#34;https://conf.fennel-lang.org/2023&#34; target=&#34;_blank&#34;&gt;talk at Fennelconf 2023&lt;/a&gt; where I explain this with some more examples.&lt;/p&gt;
&lt;h2 id=&#34;performance-check&#34;&gt;Performance check&lt;/h2&gt;
&lt;p&gt;Since the client got bigger and more complicated, let&amp;rsquo;s check the performance!
In the previous post, the client couldn&amp;rsquo;t accept a &lt;code&gt;chunked&lt;/code&gt; response, but now it can, meaning we can compare it with Luasocket&amp;rsquo;s HTTP client:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket.http&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s measure the time again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 501.31988525391 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 630.47289848328 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s about the same.
However, we can be slightly faster, if the user doesn&amp;rsquo;t need to process the body immediately:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;}) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 317.51012802124 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, the time is saved by not reading the body of the response, which shows that reading the body alone is about 200ms.
But Luasocket&amp;rsquo;s HTTP client can&amp;rsquo;t do that at all - it always processes the body, even if the generic form is used and a sink is supplied.
That&amp;rsquo;s an advantage, I would say!&lt;/p&gt;
&lt;p&gt;And, thanks to the asynchronous processing of requests, we can actually issue multiple requests at the same time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt; 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;;; luasocket&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; issuing a synchronous request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; response processed in &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms since the first request\n&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;;; fnl-http&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; issuing multiple requests. The on-success handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; will put the request number into the channel `ch`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; on completion.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/wiki/FiltersSourcesAndSinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;} #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;)]) #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-requests&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; avaiting each response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; response processed in &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms since the first request\n&amp;#34;&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; luasocket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 0.55836296081543 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.0487260818481 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.4974920749664 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.9714229106903 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.4879760742188 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 3.010272026062 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 3.6146268844604 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 4.1402359008789 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 4.6472299098969 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 5.1433019638062 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 5143.6059474945 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; fnl-http&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.3388519287109 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.4401869773865 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.5485229492188 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.6689200401306 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.7789130210876 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 1.9086010456085 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.0185270309448 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.1092948913574 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.2185280323029 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; 2.3184778690338 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;since&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 2318.8180923462 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Still &amp;lsquo;bout twice as fast!&lt;/p&gt;
&lt;p&gt;And, as you can see, the order of request completion in the asynchronous case is different, since multiple requests were processed &lt;em&gt;in parallel&lt;/em&gt;.
Well, it&amp;rsquo;s not really parallel execution, since the Lua runtime only has one thread, and all response reading is synchronous, but the moment we&amp;rsquo;ve written the request into the socket, the operating system, and networking hardware could act independently.
Thus, the response was sent, and the server on the other side received a series of requests, and probably processed them in parallel, resulting in a faster overall response.
While we wait for the data to come back to our socket, other tasks can be executed, such as making another request or processing a part of the response.
Of course, when we process the response, we do it asynchronously as well, creating opportunities for other asynchronous threads to collaborate.&lt;/p&gt;
&lt;p&gt;Neat stuff!&lt;/p&gt;
&lt;h2 id=&#34;even-further-development-i-guess&#34;&gt;Even further development, I guess?&lt;/h2&gt;
&lt;p&gt;When I started this project, I just wanted to use &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; for something more real and see if it works.
After working on it for about a month, and reading the source code of the &lt;a href=&#34;https://github.com/dakrone/clj-http&#34; target=&#34;_blank&#34;&gt;clj-http&lt;/a&gt; client, this project gradually became something like a re-implementation of &lt;code&gt;clj-http&lt;/code&gt; in Fennel.
So I changed the project name to &lt;a href=&#34;https://gitlab.com/andreyorst/fnl-http&#34; target=&#34;_blank&#34;&gt;fnl-http&lt;/a&gt;.
It&amp;rsquo;s not a one-to-one port like &lt;code&gt;async.fnl&lt;/code&gt; where I studied the source code - here all code is written from scratch without looking at other clients, but still, I tried to make it faithful.&lt;/p&gt;
&lt;p&gt;There are still a lot of parts of HTTP/1.1 that I haven&amp;rsquo;t processed, and I still have some refactoring ideas and TODOs, so stay tuned!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: fnl-http Improvements&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 01 Aug 2024 22:57:00 +0300</pubDate>
    </item><item>
      <title>Asynchronous HTTP client for Fennel</title>
      <link>https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/</link>
      <guid>https://andreyor.st/posts/2024-07-15-asynchronous-http-client-for-fennel/</guid>
      <description>&lt;p&gt;A while ago, I made a library for asynchronous programming in Fennel.
It&amp;rsquo;s based on Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; vision of asynchronous programming using only channels.
As an experiment, I&amp;rsquo;ve added a TCP support layer in that library, allowing one to create a TCP channel, and use it in the same way as a regular channel.
My original plan was to implement a small asynchronous HTTP client using that, and I&amp;rsquo;ve tried it a bunch of times in the last year.&lt;/p&gt;
&lt;p&gt;A bit later, I felt unusually burned out from programming as a hobby.
In April, I made a &lt;a href=&#34;https://andreyor.st/posts/2024-04-02-hobbies/&#34;&gt;post&lt;/a&gt; about hobbies, saying that I&amp;rsquo;d like to switch my hobbies from computers for some time.
Truth be told, I&amp;rsquo;ve been in this stance since February, and only now do I once again feel some interest in programming as a hobby.&lt;/p&gt;
&lt;p&gt;So today, I&amp;rsquo;ll walk you through why I decided to write an HTTP client almost from scratch, and why Luasocket&amp;rsquo;s HTTP client didn&amp;rsquo;t work out.&lt;/p&gt;
&lt;h2 id=&#34;luasocket-s-http-client&#34;&gt;Luasocket&amp;rsquo;s HTTP client&lt;/h2&gt;
&lt;p&gt;So, there&amp;rsquo;s an HTTP client in the &lt;a href=&#34;https://lunarmodules.github.io/luasocket/index.html&#34; target=&#34;_blank&#34;&gt;luasocket&lt;/a&gt; library.
And while it does support streaming the body through the &lt;a href=&#34;https://lunarmodules.github.io/luasocket/ltn12.html&#34; target=&#34;_blank&#34;&gt;LTN12&lt;/a&gt; module, the responses are always synchronous.
Which means, that if you have a big enough body, that you&amp;rsquo;d like to process on demand, you only get the convenience of a stream that you&amp;rsquo;ve provided as a &lt;code&gt;sink&lt;/code&gt;.
I&amp;rsquo;d like the body to be returned as some kind of stream that you can process later, reading data from the client, not from some kind of buffer.&lt;/p&gt;
&lt;p&gt;The first thing I tried was patching &lt;code&gt;http.open&lt;/code&gt; function at runtime.
Then we can open the connection and change the &lt;code&gt;close&lt;/code&gt; method on the socket, to work with our intentions.
Here&amp;rsquo;s a piece of code that does this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;open&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket.http&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.open&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; replacing `open` with our version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; using the original `open` inside&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getmetatable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h.close&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;got-body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close-handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;code&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;)] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;thankfully&amp;#34; `http.request`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; resolves `http.open`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; dynamically&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;open&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; restoring the original `http.open`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;} &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; the body is now a channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;code&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are a lot of missing details, for example, the &lt;code&gt;out&lt;/code&gt; is an ordinary channel, however, there&amp;rsquo;s a &lt;code&gt;sink&lt;/code&gt; that passed via the &lt;code&gt;opts&lt;/code&gt; table that pumps everything to it on demand.
Once the &lt;code&gt;sink&lt;/code&gt; is drained the connection is closed.&lt;/p&gt;
&lt;p&gt;All in all, this is a very stateful and shaky approach, so I didn&amp;rsquo;t want to rely on that.
Furthermore, the &lt;code&gt;sink&lt;/code&gt; is being pumped in chunks that can&amp;rsquo;t be controlled very well, making it harder to work with the data in a meaningful way.
So I knew I should do something else.&lt;/p&gt;
&lt;p&gt;I decided to write my own HTTP client based on Luasocket sockets, and streams.
Also, I wanted a bit more familiar calling interface, because Luasocket&amp;rsquo;s HTTP client is not pleasant to use in my opinion.
So let&amp;rsquo;s start with the HTTP parser!&lt;/p&gt;
&lt;h2 id=&#34;reader&#34;&gt;Reader&lt;/h2&gt;
&lt;p&gt;Actually, before parsing HTTP, we need to be able to read data from a stream.
Sockets are kinda like streams already, but we&amp;rsquo;re not there yet, so let&amp;rsquo;s create a string reader:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo\nbar\nbaz&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f6ca3475b0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;string-reader&lt;/code&gt; function accepts a string, and returns a Reader object that provides the following methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read&lt;/code&gt; - returns a specified amount of bytes, determined either by the number of bytes or by a supported read pattern.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lines&lt;/code&gt; - returns a function that when called will return the next logical line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;peek&lt;/code&gt; - returns a specified amount of bytes, without moving the caret.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;close&lt;/code&gt; - closes the Reader.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the implementation of &lt;code&gt;string-reader&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try-read-line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end&lt;/span&gt; 1)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try-read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.-)\r?\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try-read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.-)\r?$&amp;#34;&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closed&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; -1))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; -1))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;))))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit big, but there&amp;rsquo;s a reason for that - strings in Lua are immutable, and we have to maintain the state when reading.
What makes this more complicated is the &lt;code&gt;peek&lt;/code&gt; method, but we&amp;rsquo;ll get to that later.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;make-reader&lt;/code&gt; function is a generic Reader constructor, that accepts a table of optional methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-bytes&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;peek&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-bytes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))) #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;read-line &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[] #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;peek&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;peek &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Reader&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Reader:&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;)}))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it just wraps everything with &lt;code&gt;pcall&lt;/code&gt; and passes the specified &lt;code&gt;source&lt;/code&gt; to the methods.
Perhaps, there&amp;rsquo;s a more clear way of doing this, but it&amp;rsquo;s fine for now.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a &lt;code&gt;file-reader&lt;/code&gt;, for example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.open&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; #(&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:seek&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))})))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It accepts either a file handle or a string that is treated as a path to open the file.
It&amp;rsquo;s much shorter than the &lt;code&gt;string-reader&lt;/code&gt; since files can be seek&amp;rsquo;d and the file object is already stateful.&lt;/p&gt;
&lt;p&gt;In the end, we can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo\nbar\nbaz\nqux&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;o&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;qux&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ll be implementing a socket Reader soon, but before that, let&amp;rsquo;s start implementing a set of functions to generate HTTP messages.&lt;/p&gt;
&lt;h2 id=&#34;http-generation&#34;&gt;HTTP generation&lt;/h2&gt;
&lt;p&gt;We start with the &lt;code&gt;build-http-request&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;HTTP-VERSION&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request-target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Formaths the HTTP request string as per the HTTP/1.1 spec.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s %s %s\r\n%s\r\n%s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.upper&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;request-target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;HTTP-VERSION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, it&amp;rsquo;s just a &lt;code&gt;string.format&lt;/code&gt; call, which we fill in with specific parts.
The &lt;code&gt;method&lt;/code&gt; and &lt;code&gt;request-target&lt;/code&gt; are mandatory arguments, as nothing will work without them.
&lt;code&gt;?headers&lt;/code&gt; and &lt;code&gt;?content&lt;/code&gt; on the other hand are optional.
Let&amp;rsquo;s implement the &lt;code&gt;headers-&amp;gt;string&lt;/code&gt; function now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header-&amp;gt;string&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Converts `header` and `value` arguments into a valid HTTP header
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;string.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Converts a `headers` table into a multiline string of HTTP headers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;icollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pairs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header-&amp;gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We simply check whether &lt;code&gt;headers&lt;/code&gt; is not &lt;code&gt;nil&lt;/code&gt;, and if it has any keys.
If so, we iterate over the headers table, and convert each pair to a string, then concatenating the resulting table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Content-Type: application/json\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;utils.capitalize-header&lt;/code&gt; function accepts a string in any case, and transforms it to an HTTP case, meaning each word is capitalized and separated with a dash:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo_bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo-Bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;FooBar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo-Bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.capitalize-header&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;FOO BAR&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Foo-Bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll let you think about implementation, as I&amp;rsquo;m not particularly fond of my own :)&lt;/p&gt;
&lt;p&gt;With that, we can generate a request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost:1234&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/plain&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;GET / HTTP/1.1\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Content-Type: text/plain\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Host: localhost:1234\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;foobar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While we&amp;rsquo;re at it, let&amp;rsquo;s make the &lt;code&gt;build-http-response&lt;/code&gt; function too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Formats the HTTP response string as per the HTTP/1.1 spec.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s %s %s\r\n%s\r\n%s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;HTTP-VERSION&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers-&amp;gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same as before, &lt;code&gt;string.format&lt;/code&gt;, filling missing parts, no new functions used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    200 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;foo\&amp;#34;: \&amp;#34;bar\&amp;#34;}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 200 OK\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Content-Type: application/json\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{\&amp;#34;foo\&amp;#34;: \&amp;#34;bar\&amp;#34;}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can parse these using our Reader objects.&lt;/p&gt;
&lt;h2 id=&#34;http-parsing&#34;&gt;HTTP Parsing&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start with &lt;code&gt;parse-http-response&lt;/code&gt;, as we&amp;rsquo;re more likely to parse responses, rather than requests, as this library is mainly a client.
We&amp;rsquo;ll write &lt;code&gt;parse-http-request&lt;/code&gt; as well, but just for fun.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Obviously, this isn&amp;rsquo;t all we really need, but it&amp;rsquo;s a good start.
First, let&amp;rsquo;s parse the status line, i.e. the first line of the response: &lt;code&gt;HTTP/1.1 200 OK&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-response-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;major&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;minor&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^/]+)/(%d).(%d)&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tonumber&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;major&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tonumber&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;minor&lt;/span&gt;)})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.as-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s/%s.%s +%s +&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.protocol-version.name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.protocol-version.major&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.protocol-version.minor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res.status&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gmatch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^ ]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-response-status-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may be wondering, why these functions accept &lt;code&gt;read-fn&lt;/code&gt;.
Well, this is something we need to do because we&amp;rsquo;ll later pass in a socket-channel as a stream.&lt;/p&gt;
&lt;p&gt;With these functions, we can read and parse the status line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 200 OK\r\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may also wonder, why the loop doesn&amp;rsquo;t just continue to read the &lt;code&gt;reason-phrase&lt;/code&gt;, instead relying on &lt;code&gt;status:gsub&lt;/code&gt;.
Well, reason can include spaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 404 NOT FOUND\r\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;NOT FOUND&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 404}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Onto headers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-header&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; *([^:]+) *: *(.*)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?headers&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\r&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-header&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;header&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This one is tail-recursive, accumulating parsed headers in the &lt;code&gt;?headers&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Content-Type: application/json\r\nConnection: close\r\n\n\r&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, for the body, we just return the reader as it is, as we&amp;rsquo;ve already read from it all the necessary data, and the rest are the contents of the request.
Together, we get a fully parsed response:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP/1.1 200 OK\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Content-Type: application/json\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Connection: close\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\r
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;{\&amp;#34;foo\&amp;#34;: \&amp;#34;bar\&amp;#34;}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55a54832b810&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can ensure that the parsed response can be encoded back:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt; 200 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason-phrase&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s parse the request for completeness:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-request-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;field&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.as-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;part&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gmatch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^ ]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:method&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http-version&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-request-status-line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-request-status-line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-request&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-request-status-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s similar, but we need to parse the status line a bit differently.
Same as before, let&amp;rsquo;s ensure that we can do both:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can start implementing the client itself!&lt;/p&gt;
&lt;h2 id=&#34;async-dot-fnl&#34;&gt;Async.fnl&lt;/h2&gt;
&lt;p&gt;For communication, we&amp;rsquo;ll use already existing TCP channels, that enclose socket objects.
Although, we&amp;rsquo;ll need a small modification to the &lt;code&gt;async.fnl&lt;/code&gt; library, as currently it always reads data in chunks of fixed size.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the function that returns a socket channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-chunk-size&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern-or-size&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern-or-size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket-channel&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1024 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1024 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ready&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:puts&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv.puts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:takes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.takes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:put!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:put!&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:take!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offer!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ready&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ready&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:take!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enqueue?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:chunk-size&lt;/span&gt; 1024
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:set-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-chunk-size&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;SocketChannel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;SocketChannel:&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;)}))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket.select&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;] 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:send&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;j&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;j&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:closed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recv&lt;/span&gt;) 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wait?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wait?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ready&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:receive&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c.chunk-size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:closed&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:timeout&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 10)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a lot of code, but in reality, it isn&amp;rsquo;t that complicated.
The &lt;code&gt;socket-channel&lt;/code&gt; function is responsible for three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a channel, that has separate queues for puts and takes, such that when we put something to a channel, we won&amp;rsquo;t be able to read it back immediately.&lt;/li&gt;
&lt;li&gt;Creating an asynchronous loop that waits for data from the socket, and puts it into the receive queue&lt;/li&gt;
&lt;li&gt;Creating another asynchronous loop, that waits data on the channel, and puts it into the socket.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These loops account for timeouts, as we&amp;rsquo;re going to set the socket timeout to &lt;code&gt;0&lt;/code&gt;, to ensure non-blocking behavior.
Both asynchronous loops employ their own timeout handling.&lt;/p&gt;
&lt;p&gt;The resulting object is a channel, but with some custom methods to account for its duplex nature.
And, there are also other properties, such as &lt;code&gt;chunk-size&lt;/code&gt; and &lt;code&gt;set-chunk-size&lt;/code&gt; which we&amp;rsquo;re going to use with our streams.&lt;/p&gt;
&lt;p&gt;Notice, how the second &lt;code&gt;go-loop&lt;/code&gt; has a &lt;code&gt;wait?&lt;/code&gt; argument.
Because the channel is buffered, it will happily read everything until the buffer is full, which is not ideal, since we may want to change the &lt;code&gt;chunk-size&lt;/code&gt; later.
So we need to delay the actual read, which we do in the &lt;code&gt;take!&lt;/code&gt; method using &lt;code&gt;offer!&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;tcp.chan&lt;/code&gt; function acts as a constructor for TCP channels:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tcp.chan&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Creates a channel that connects to a socket via `host` and `port`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Optionally accepts a transducer `xform`, and an error handler.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`err-handler` must be a fn of one argument - if an exception occurs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;during transformation it will be called with the thrown value as an
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;argument, and any non-nil return value will be placed in the channel.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The read pattern f a socket can be controlled with the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`set-chunk-size` method.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;tcp module requires luasocket&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:localhost&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-try&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket.connect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:settimeout&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket-channel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err-handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;err&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is all we need on the &lt;code&gt;async.fnl&lt;/code&gt; side of things.
No more patching Luasocket&amp;rsquo;s HTTP client.&lt;/p&gt;
&lt;p&gt;Now we can start implementing our own client.&lt;/p&gt;
&lt;h2 id=&#34;http-client&#34;&gt;HTTP client&lt;/h2&gt;
&lt;p&gt;We already have most of the things we need, but we need to change the &lt;code&gt;parse-http-response&lt;/code&gt; a bit.
Remember, our function returns the body as the Reader, but our source is actually a channel.
We can account for that by passing in an appropriate &lt;code&gt;read-fn&lt;/code&gt; function but our users shouldn&amp;rsquo;t deal with that.
Instead, the body should provide proper Reader methods, so let&amp;rsquo;s create a &lt;code&gt;body-reader&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body-reader&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read-line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:find&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.sub&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;) 2))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-more?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-content&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected number of bytes to peek&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;len&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer&lt;/span&gt;))))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, that&amp;rsquo;s a lot of code again.
The reason for that is the &lt;code&gt;peek&lt;/code&gt; method - same as for strings, we need to implement a way to peek at data without modifying the reader, or at least hide the modification from the user.
This is essentially what this function does - it creates a string buffer that we can act upon, accounting for possible data in it before actually reading from the channel itself.&lt;/p&gt;
&lt;p&gt;With that function, we can update &lt;code&gt;parse-http-response&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-http-response&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt; {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-response-status-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-fn&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers.Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unsupported coersion method &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, I&amp;rsquo;ve added another parameter with options.
Right now, there&amp;rsquo;s only one option &lt;code&gt;as&lt;/code&gt; that will choose how to return the body.
Specifying &lt;code&gt;{:as :raw}&lt;/code&gt; to this function will return the contents of the reader.
And &lt;code&gt;{:as :stream}&lt;/code&gt; will return the stream itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;, we can write the &lt;code&gt;request&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?opts&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Makes a `method` request to the `url`, returns the parsed response,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;containing a stream data of the response. The `method` is a string,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;describing the HTTP method per the HTTP/1.1 spec. The `opts` is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;table containing the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:async?` - a boolean, whether the request should be asynchronous.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  The result is an instance of a `promise-chan`, and the body must
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  be read inside of a `go` block.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:headers` - a table with the HTTP headers for the request
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:body` - an optional string body.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:as` - how to coerce the output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Several options available for the `as` key:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:stream` - the body will be a stream object with a `read` method.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:raw` - the body will be a string.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  This is the default value for `as`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;When supplying a non-string body, headers should contain a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;content-length\&amp;#34; key. For a string body, if the \&amp;#34;content-length\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;header is missing it is automatically determined by calling the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`length` function, ohterwise no attempts at detecting content-length
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;are made.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http-parser.parse-url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?opts&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pairs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.headers&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:content-length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;))}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;utils.format-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-http-request&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tcp.chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts.async?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;promise-chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http-parser.parse-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http-parser.parse-http-response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-read-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re still missing some important parts, but we&amp;rsquo;ll get to those in a bit.
This function is long, but it&amp;rsquo;s not that complicated.&lt;/p&gt;
&lt;p&gt;First, we parse the given &lt;code&gt;url&lt;/code&gt; into its components, mainly the &lt;code&gt;host&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt;.
Then, we prepare the default &lt;code&gt;opts&lt;/code&gt; table to include &lt;code&gt;as&lt;/code&gt; key and &lt;code&gt;async?&lt;/code&gt; key if none were passed.&lt;/p&gt;
&lt;p&gt;Next, we prepare headers.
The HTTP spec requires the &lt;code&gt;Host&lt;/code&gt; header, so we put it in based on the parsed URL.
The &lt;code&gt;path&lt;/code&gt; part of the request is then formatted from the rest data from the parsed URL.&lt;/p&gt;
&lt;p&gt;Finally, we &lt;code&gt;build-http-request&lt;/code&gt;, using the &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; if supplied.
And create the &lt;code&gt;tcp.chan&lt;/code&gt; using the &lt;code&gt;parsed&lt;/code&gt; object that contains &lt;code&gt;host&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt; needed for the constructor.&lt;/p&gt;
&lt;p&gt;Then, if &lt;code&gt;opts.async?&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, we create a &lt;code&gt;promise-chan&lt;/code&gt;, which is like Clojure&amp;rsquo;s &lt;code&gt;promise&lt;/code&gt;, which is only computed once, and then returns the same result over and over.
We start the &lt;code&gt;go&lt;/code&gt; thread, in which we asynchronously put the request into the socket channel, and then we asynchronously parse the response supplying our &lt;code&gt;read-fn&lt;/code&gt; with the &lt;code&gt;&amp;lt;!&lt;/code&gt; function to take from the channel asynchronously.
And we return &lt;code&gt;res&lt;/code&gt; - the promise channel I mentioned earlier.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;opts.async?&lt;/code&gt; wasn&amp;rsquo;t true, we do all the same thing, but in a blocking way, using &lt;code&gt;&amp;gt;!!&lt;/code&gt; and &lt;code&gt;&amp;lt;!!&lt;/code&gt; to work with the channel.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at &lt;code&gt;parse-url&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-authority&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^@]+)@&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:(%d+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;@([^:]+)&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;authority&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^:]+)&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-url&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^([^:]+)://&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-authority&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;//([^/]+)/&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^([^/]+)/&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:https&lt;/span&gt; 443 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http&lt;/span&gt; 80))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;//[^/]+/([^?#]+)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%?([^#]+)#?&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#([^?]+)%??&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;userinfo&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing special, just some patterns to match components of the URL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://lua-users.org/?some-query-param=some-value&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-users.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 443
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-query-param=some-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the &lt;code&gt;format-path&lt;/code&gt; function constructs the path back:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-path&lt;/span&gt; [{&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or path &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;query&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fragment&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what it does on the previously parsed URL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-path&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua-users.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:port&lt;/span&gt; 443
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:query&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-query-param=some-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:scheme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/?some-query-param=some-value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, the mysterious &lt;code&gt;make-read-fn&lt;/code&gt; function creates a function that will work with our socket-channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-read-fn&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;receive&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Returns a function that receives data from a socket by a given
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`pattern`.  The `pattern` can be either `\&amp;#34;*l\&amp;#34;`, `\&amp;#34;*a\&amp;#34;`, or a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;number of bytes to read.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:set-chunk-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;receive&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;src&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since our channel does reading on demand, we can&amp;rsquo;t pass the chunk-size/pattern in, so we use the &lt;code&gt;set-chunk-size&lt;/code&gt; method instead.
Paired with delayed read, I&amp;rsquo;ve explained earlier, this works really well.&lt;/p&gt;
&lt;p&gt;With all of that, we&amp;rsquo;re ready to do some requests!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE html PUBLIC \&amp;#34;-//W3C//DTD HTML 4.01 Transitional//EN\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;title&amp;gt;lua-users.org&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;meta http-equiv=\&amp;#34;content-type\&amp;#34; content=\&amp;#34;text/html; charset=ISO-8859-1\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;LINK TYPE=\&amp;#34;text/css\&amp;#34; REL=\&amp;#34;stylesheet\&amp;#34; HREF=\&amp;#34;/styles/main.css\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;img src=\&amp;#34;/images/lua-users-org.png\&amp;#34; alt=\&amp;#34;lua-users.org logo\&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;br clear=all&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;b&amp;gt;lua-users.org&amp;lt;/b&amp;gt; is an internet site for and by users of the programming language Lua.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;To find out what Lua is and for documentation, downloads, mailing list info, etc. please visit the &amp;lt;a href=\&amp;#34;http://www.lua.org/\&amp;#34;&amp;gt;official Lua web site&amp;lt;/a&amp;gt;.  The &amp;lt;b&amp;gt;lua-users.org&amp;lt;/b&amp;gt; web is not affiliated with Tecgraf.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Currently available resources:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;/wiki/\&amp;#34;&amp;gt;lua-users wiki&amp;lt;/a&amp;gt; - collaborative web site
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;/lists/lua-l/\&amp;#34;&amp;gt;lua-l archive&amp;lt;/a&amp;gt; - searchable web archive of
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;        the official Lua mailing list
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;MiniCharter.html\&amp;#34;&amp;gt;lua-users.org mini charter&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;    &amp;lt;li&amp;gt; &amp;lt;a href=\&amp;#34;Acknowledgements.html\&amp;#34;&amp;gt;acknowledgements&amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Accept-Ranges&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1055&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:03:00 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ETag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;61acad05-41f\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Last-Modified&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sun, 05 Dec 2021 12:13:57 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nginx/1.20.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max-age=0;&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, we can use &lt;code&gt;:as :stream&lt;/code&gt;, and process the stream later:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55d7090707c0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Accept-Ranges&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1055&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:03:47 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ETag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;61acad05-41f\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Last-Modified&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sun, 05 Dec 2021 12:13:57 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nginx/1.20.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max-age=0;&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE html PUBLIC \&amp;#34;-//W3C//DTD HTML 4.01 Transitional//EN\&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, writing &lt;code&gt;(http.request :get ...)&lt;/code&gt; all the time, is a bit tedious.
Let&amp;rsquo;s instead define functions for each HTTP method.
And, to do so, we&amp;rsquo;ll use macros, because I&amp;rsquo;m too lazy, and I don&amp;rsquo;t want to write documentation for each function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Defines an HTTP method for the given `method`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:http.&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts#&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fnl/arglist&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fnl/docstring&lt;/span&gt; ,(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Makes a `&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.upper&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;` request to the `url`, returns the parsed response,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;containing a stream data of the response. The `method` is a string,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;describing the HTTP method per the HTTP/1.1 spec. The `opts` is a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;table containing the following keys:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:async?` - a boolean, whether the request should be asynchronous.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  The result is an instance of a `promise-chan`, and the body must
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  be read inside of a `go` block.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:headers` - a table with the HTTP headers for the request
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:body` - an optional string body.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:as` - how to coerce the output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Several options available for the `as` key:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:stream` - the body will be a stream object with a `read` method.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;- `:raw` - the body will be a string.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  This is the default value for `as`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;When supplying a non-string body, headers should contain a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;content-length\&amp;#34; key. For a string body, if the \&amp;#34;content-length\&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;header is missing it is automatically determined by calling the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`length` function, ohterwise no attempts at detecting content-length
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;are made.&amp;#34;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.request&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;opts#&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;post&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;patch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;options&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;trace&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;head&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;delete&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-http-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;connect&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can call any HTTP method by just writing &lt;code&gt;(http.method-name ...)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://lua-users.org/&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;Reader&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; 0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55d7095dbb20&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Accept-Ranges&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1055&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:08:28 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ETag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;61acad05-41f\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Last-Modified&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sun, 05 Dec 2021 12:13:57 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nginx/1.20.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max-age=0;&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we can even see the documentation for each method in our editor:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-07-15-asynchronous-http-client-for-fennel/docs.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now, that &lt;code&gt;body-reader&lt;/code&gt;, with a custom buffer, seemed a bit out of the way, so let&amp;rsquo;s use it for good.&lt;/p&gt;
&lt;h2 id=&#34;json-parsing&#34;&gt;JSON parsing&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s extend our &lt;code&gt;parse-http-response&lt;/code&gt; function with another &lt;code&gt;as&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parsed-headers.Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:*a&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json.parse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unsupported coersion method &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---- 8&amp;lt; ----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can implement a simple JSON parser:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Accepts a reader object `rdr`, that supports `peek`, and `read`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;methods.  Parses the contents to a Lua table.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-arr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;t&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 4))) (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 4) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 5))) (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 5) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;null&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 4))) (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 4) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[ \t\n]&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[-0-9]&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-num&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: end of stream&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: unexpected token (&amp;#39;%s&amp;#39; (code %d))&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:byte&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, let&amp;rsquo;s look at &lt;code&gt;parse-string&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-string&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;escaped?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\\&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;escaped?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;escaped?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function handles strings, and escaped patterns withing set strings, like nested strings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\&amp;#34;foo \\\&amp;#34;bar\\\&amp;#34;\&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo \&amp;#34;bar\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s look at the &lt;code&gt;parse-arr&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-arr&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: expected &amp;#39;,&amp;#39; or &amp;#39;]&amp;#39; after the value: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   []))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function accepts the &lt;code&gt;parse&lt;/code&gt; callback to parse nested values, so if we try to parse an array of strings, we&amp;rsquo;ll call &lt;code&gt;parse&lt;/code&gt; on each value, and then expect either a colon or the closing bracket to mark the end of the array.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[\&amp;#34;a\&amp;#34;, \&amp;#34;b\&amp;#34;]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;parse-obj&lt;/code&gt; works for objects in a similar way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-obj&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;key &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;key &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;skip-space&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: expected &amp;#39;,&amp;#39; or &amp;#39;}&amp;#39; after the value: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;JSON parse error: expected colon after the key: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;key&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except, it waits for the &lt;code&gt;:&lt;/code&gt; after each key, and then the value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;parse &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader.string-reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{\&amp;#34;arr\&amp;#34;: [\&amp;#34;a\&amp;#34;, \&amp;#34;b\&amp;#34;]}&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:arr&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, there&amp;rsquo;s the &lt;code&gt;parse-num&lt;/code&gt; and code to parse Booleans, and &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse-num&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numbers&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:peek&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[-0-9.eE+]&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1) (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numbers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tonumber&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numbers&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rdr&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that, we can call &lt;code&gt;http.get&lt;/code&gt; passing it &lt;code&gt;{:as :json}&lt;/code&gt; as opts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:json&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:X-Amzn-Trace-Id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-6695183d-27c59aff535ae9f11df8c98d&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;185.169.167.87&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Credentials&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Access-Control-Allow-Origin&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;keep-alive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Length&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;199&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Content-Type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Date&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mon, 15 Jul 2024 12:38:21 GMT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:Server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gunicorn/19.9.0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol-version&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:major&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minor&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:reason-phrase&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:status&lt;/span&gt; 200}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And our body was successfully parsed.&lt;/p&gt;
&lt;h2 id=&#34;asynchronous-http-calls&#34;&gt;Asynchronous HTTP calls&lt;/h2&gt;
&lt;p&gt;Now, this client is asynchronous, meaning we can download lots of resources simultaneously.
I&amp;rsquo;m not saying &lt;em&gt;in parallel&lt;/em&gt;, because there are no threads in Lua, but still, we can process several requests at once using our asynchronous library.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s define a simple &lt;code&gt;time&lt;/code&gt; macro first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;socket.gettime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clock#&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;end#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start#&lt;/span&gt;) 1000) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; ms&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res#&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With it, we can measure the execution time of a body.
Let&amp;rsquo;s make three asynchronous requests, that upon completion will count the lengths of the body for each, and return their sum:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 3)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lengths&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 530.24077415466 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;597
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In comparison, three synchronous requests, take almost twice as much time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:connection&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;http.get&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:raw&lt;/span&gt;})]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.body&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.body&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c.body&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 1047.5831031799 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;597
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the reference, here&amp;rsquo;s Luasocket&amp;rsquo;s HTTP client:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket.http&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lhttp.request&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt; 1919.6438789368 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;717
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(Note, the resulting length is different, because Luasocket specifies its user-agent, and httpbin includes it in the answer.)&lt;/p&gt;
&lt;h2 id=&#34;further-development&#34;&gt;Further development&lt;/h2&gt;
&lt;p&gt;Now, of course, that&amp;rsquo;s not all that needs to be implemented.
In its current state, this client doesn&amp;rsquo;t support responses that do not specify the Content-Length or produce a response body in chunked encoding.
HTTPS is out of the question for now too.
Most of the code just takes a &amp;ldquo;happy path&amp;rdquo; without much thought given to errors or more complicated scenarios.
But it&amp;rsquo;s fine, I can always make it better down the line.&lt;/p&gt;
&lt;p&gt;But all in all, it was a fun experiment, and I&amp;rsquo;m feeling better, as I finally have some use for &lt;code&gt;async.fnl&lt;/code&gt;.
You can find the source code for this project on my GitLab profile.
And by the way, even though it is written in Fennel and uses some Fennel libraries, like &lt;code&gt;async.fnl&lt;/code&gt;, this library works with ordinary Lua:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Lua 5.4.4  Copyright (C) 1994-2022 Lua.org, PUC-Rio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; http = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; http.get(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;, {headers = {connection = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}}).body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;headers&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Host&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;httpbin.org&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;X-Amzn-Trace-Id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Root=1-6695424f-01e0510f2ab49b9f46bd51dc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;origin&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;185.165.163.78&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; http.get(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;http://httpbin.org/get&amp;#34;&lt;/span&gt;, {headers = {connection = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;}, as = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;stream&amp;#34;&lt;/span&gt;}).body
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reader: 0x55a6c0eff710
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So if you like what you see, but you don&amp;rsquo;t use Fennel, you can still try out this library.
It just needs to be compiled first.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s all from me, so… thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Asynchronous HTTP client for Fennel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 15 Jul 2024 20:08:00 +0300</pubDate>
    </item><item>
      <title>Why today&#39;s phones are so boooooring?</title>
      <link>https://andreyor.st/posts/2024-06-11-why-todays-phones-are-so-boooooring/</link>
      <guid>https://andreyor.st/posts/2024-06-11-why-todays-phones-are-so-boooooring/</guid>
      <description>&lt;p&gt;So, here&amp;rsquo;s a question - when were you last excited for a new phone?
Well, I mean &lt;em&gt;really&lt;/em&gt; excited?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the thing.
Phones are so boring today that most retail stores show you the &lt;strong&gt;backside of the phone&lt;/strong&gt;.
Because from the front they all look exactly the same.&lt;/p&gt;
&lt;p&gt;Do you remember the old days when phone manufacturers fought for your money by trying to make cool-looking phones?
Nokia and Siemens were legendary rivals, at least in my region.
And then Sony Ericsson came to the party and nuked Siemens out of the competition for a few years - no one talked about Siemens.
And then Motorola came with their Razor series and woooh!
Just look up old phone magazines - they&amp;rsquo;re filled with amazing designs.&lt;/p&gt;
&lt;p&gt;I still have my old Nokia and Sony Ericsson phones:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-06-11-why-todays-phones-are-so-boooooring/my-old-phones.jpg&#34;
         alt=&#34;Figure 1: Both of the phones feature buttons above the screen. Nokia had them cleverly hidden with the ability to slide the screen in both ways which were used both as media controls and for some games. You could comfortably game on these phones without the main keyboard!&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Both of the phones feature buttons above the screen. Nokia had them cleverly hidden with the ability to slide the screen in both ways which were used both as media controls and for some games. You could comfortably game on these phones without the main keyboard!&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Yes, they&amp;rsquo;re busted, but I still love them - they look rad.&lt;/p&gt;
&lt;p&gt;Now look at the typical online marketplace for phones:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-06-11-why-todays-phones-are-so-boooooring/best-sellers-amazon.png&#34;
         alt=&#34;Figure 2: Current best-sellers at amazon.com&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Current best-sellers at amazon.com&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Apart from the wallpaper at the front, these phones all look similar - it&amp;rsquo;s a black rectangle.
The backside is where the design is supposed to happen today, yet most phones are just some variation of mat glass, leather, or just some colored plastic for cheaper ones.&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;*duh*&lt;/pre&gt;
&lt;p&gt;Smartphones are a pretty much a figured-out tech since 2007.
It has to be a black rectangle, because the screen is the most important part, so it has to cover all of the available area and it was refined over the years until no borders were left to spare.
And the backside is pretty much what is left for creativity, but you can&amp;rsquo;t do much with how big camera modules are today, because people demand good cameras even in cheaper segments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, you could say that.
But do you know that other tech, that was figured out and for a much longer time than the Smartphones?
I&amp;rsquo;ll give you a hint, it contains the latter part of the word &amp;ldquo;smartphone&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Headphones&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Headphones haven&amp;rsquo;t really advanced much since the 80s.
I mean, they did, and quite a bit in the &lt;abbr title=&#34;In Ear Monitor&#34;&gt;IEM&lt;/abbr&gt; field, but not radically overall.
One of the most balanced studio headphones as of today are Sennheiser HD 600 were released in 1997.&lt;/p&gt;
&lt;p&gt;I know, there are all these different technologies for producing sound, like dynamic, planar-magnetic, electrostatic drivers, MEMs, and possibly more.
But we have had great audio since the 80s, you don&amp;rsquo;t have to buy new headphones every few years - the technology is already pretty much maxed out our hearing capabilities.&lt;/p&gt;
&lt;p&gt;We approach the same scenario with smartphone screens - ~500 &lt;abbr title=&#34;pixel per inch&#34;&gt;ppi&lt;/abbr&gt; on a 7-inch screen is already far beyond the required amount to not-see the individual pixels.
It&amp;rsquo;s like drivers in headphones - the sound resolution is way beyond human hearing, so there&amp;rsquo;s no need for more advancements to be made.
Different drivers have different response times, sure, but it&amp;rsquo;s the same with screens if you think about refresh rates.&lt;/p&gt;
&lt;p&gt;But I digress.
Have a look at modern headphones:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-06-11-why-todays-phones-are-so-boooooring/premium-headphones.png&#34;
         alt=&#34;Figure 3: headphones.com catalog&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;headphones.com catalog&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Yes, these all are premium products, but even consumer-grade ones are competing in design and ergonomics:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-06-11-why-todays-phones-are-so-boooooring/headphones.png&#34;
         alt=&#34;Figure 4: headphones.com catalog&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;headphones.com catalog&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Think about it - headphones, essentially, are just ovals or circles - you don&amp;rsquo;t need all these fancy earcup designs, materials, and whatnot.
Again, one of the best-sounding headphones is just an oval with a perforated mesh on the outer side:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-06-11-why-todays-phones-are-so-boooooring/hd600.png&#34;
         alt=&#34;Figure 5: A product photo from sennheiser.com&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;A product photo from sennheiser.com&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You don&amp;rsquo;t need all of these cool-looking shapes on the earcup, yet headphone manufacturers do it because it is a form of expression.
Art, even.&lt;/p&gt;
&lt;p&gt;And if you look at premium smartphones, apart from a back rectangle on the front, what do you get on the back usually?
A mat glass with too many cameras and a logo that you gonna cover with a phone case anyway.&lt;/p&gt;
&lt;p&gt;When Samsung showed up their new foldable phones, I got excited for a bit, but the foldable screen tech is still not ready for prime time.
And again, these phones all pretty much look the same.
They do have a different hinge design, and often the outer shell has a more stylized look, but still, do you remember the old foldable phones?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2024-06-11-why-todays-phones-are-so-boooooring/old-foldables.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Why today&amp;rsquo;s phones are so boooooring?&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Why today&#39;s phones are so boooooring?&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 11 Jun 2024 04:10:00 +0300</pubDate>
    </item><item>
      <title>Lazy state machines</title>
      <link>https://andreyor.st/posts/2024-05-15-lazy-state-machines/</link>
      <guid>https://andreyor.st/posts/2024-05-15-lazy-state-machines/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m not sure if this is a new thing or not, and I&amp;rsquo;m too lazy to look it up as it&amp;rsquo;s 3 AM right now, so here it is.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been thinking about state machines lately, and how Clojure&amp;rsquo;s multimethods are a cool way to implement a state machine.
Multimethods are somewhat like pattern matching, in a way, and you can use them to do some declarative programming in Clojure, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;identity&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; 0 [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; 1 [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:default&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; 5) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; 120&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, here, we&amp;rsquo;re declaring the &lt;code&gt;factorial&lt;/code&gt; multimethod that dispatches on numbers.
Let&amp;rsquo;s ignore negative numbers for now - pretend we&amp;rsquo;re ancient Greeks, and there is no such thing as a negative number.&lt;/p&gt;
&lt;p&gt;So, when &lt;code&gt;factorial&lt;/code&gt; sees a value of &lt;code&gt;0&lt;/code&gt;, it simply returns &lt;code&gt;1&lt;/code&gt;.
The same thing happens if it sees &lt;code&gt;1&lt;/code&gt;.
Otherwise, we&amp;rsquo;ll multiply the number with the result of calling &lt;code&gt;factorial&lt;/code&gt; with the said number decreased by &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In reality, there&amp;rsquo;s and &lt;code&gt;if&lt;/code&gt; hiding in here, as we might have just written factorial the conventional way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 0) 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1) 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:else&lt;/span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;factorial&lt;/span&gt; 5) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; 120&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s the same thing, except we&amp;rsquo;ve avoided concretion of our function, allowing it to be extended with arbitrary dispatch values from outside, without modifying existing code.&lt;/p&gt;
&lt;p&gt;I say it&amp;rsquo;s declarative because we&amp;rsquo;re declaring how a function should behave, given a specific input.
I say it&amp;rsquo;s like pattern matching because we kinda match a pattern with the dispatching function.&lt;/p&gt;
&lt;p&gt;E.g. we can write a pattern matching function that can do stuff based on a pattern of arguments given:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [0 0] [&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;draw&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [1 0] [&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;win&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [0 1] [&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loose&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [1 1] [&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;snake eyes&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; 1 1) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; &amp;#34;snake eyes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s not quite pattern matching, as it doesn&amp;rsquo;t do binding, and there&amp;rsquo;s no match-all/I-don&amp;rsquo;t-care clause, but it can be used like that, and we certainly do.&lt;/p&gt;
&lt;p&gt;Now, the &lt;code&gt;factorial&lt;/code&gt; example is also a kind of a state machine.
When it sees the number &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt; its action is simple - return &lt;code&gt;1&lt;/code&gt; and halt.
If it sees anything else, it changes the state by decreasing a number, and proceeds.
After the state reaches &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt;, the stack of actions is reduced, and we get the final result.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s a problem.
Such a state machine can&amp;rsquo;t run for an arbitrary amount of time - it will consume a lot of the stack, and eventually fail.
How can we avoid that?&lt;/p&gt;
&lt;p&gt;We know, there&amp;rsquo;s a way of doing recursion in Clojure, using the &lt;code&gt;recur&lt;/code&gt; special.
It isn&amp;rsquo;t like a proper recursion though, rather, it&amp;rsquo;s a jump to the beginning of the function which also rebinds its arguments.
It&amp;rsquo;s a handy thing, but it can&amp;rsquo;t handle mutual recursion.&lt;/p&gt;
&lt;p&gt;The other way of doing recursion in Clojure is the &lt;code&gt;trampoline&lt;/code&gt; function.
Instead of calling the function you want to recurse into, you return it as a callback, and &lt;code&gt;trampoline&lt;/code&gt; executes it instead.
Because of that the stack is constantly incremented and decremented, but we can&amp;rsquo;t have non-tail mutual recursion.&lt;/p&gt;
&lt;p&gt;Yet, there&amp;rsquo;s a way of having non-tail mutual recursion that doesn&amp;rsquo;t blow up the stack - lazy sequences!&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a great example, a lazy sequence of Fibonacci numbers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib-seq&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib-seq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;drop &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib-seq&lt;/span&gt; 0 1))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt; 9) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; 55&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; (1 1 2 3 5 8 13 21 34 55)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;10 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fib-seq&lt;/span&gt; 0 1)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; (0 1 1 2 3 5 8 13 21 34)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, &lt;code&gt;fib-seq&lt;/code&gt; creates a lazy sequence by constantly calling itself.
Its call is delayed until we consume the sequence, so it acts mostly like a &lt;code&gt;trampoline&lt;/code&gt;, except we can retain all previous results.&lt;/p&gt;
&lt;p&gt;Thinking of this, I came up with this kind of state machine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This machine is simple - when it sees the state &lt;code&gt;:a&lt;/code&gt; it will produce the &lt;code&gt;&amp;quot;A&amp;quot;&lt;/code&gt; as a result, and change to the state &lt;code&gt;:c&lt;/code&gt;.
In state &lt;code&gt;:c&lt;/code&gt; it produces the result &lt;code&gt;&amp;quot;C&amp;quot;&lt;/code&gt; and changes to the state &lt;code&gt;:b&lt;/code&gt;.
Finally, in the state &lt;code&gt;:b&lt;/code&gt; the machine produces the result &lt;code&gt;&amp;quot;B&amp;quot;&lt;/code&gt; and doesn&amp;rsquo;t change its state.
Then it halts.
So, if we call &lt;code&gt;(machine [:a])&lt;/code&gt; we&amp;rsquo;ll get the following list &lt;code&gt;(&amp;quot;A&amp;quot; &amp;quot;C&amp;quot; &amp;quot;B&amp;quot; &amp;quot;done&amp;quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One important observation would be that, unlike the &lt;code&gt;fibbonaci&lt;/code&gt;, this state machine accepts a sequence of states, and modifies it to change state.
This means that we can provide more tasks in a sequence, like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, since this state machine is lazy, we don&amp;rsquo;t have to consume all of its results, as it might never actually halt, say there&amp;rsquo;s one more state &lt;code&gt;:d&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No other state triggers this one, so the machine would always halt if we only gave it states &lt;code&gt;:a&lt;/code&gt;, &lt;code&gt;:b&lt;/code&gt;, and &lt;code&gt;:c&lt;/code&gt;.
However, if we give it the state &lt;code&gt;:d&lt;/code&gt; manually, we would get this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;10 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;drop &lt;/span&gt;1000000000 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;machine&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:d&lt;/span&gt;])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unless I used &lt;code&gt;take&lt;/code&gt; we would&amp;rsquo;ve stuck on the &lt;code&gt;:d&lt;/code&gt; state forever.
However, it doesn&amp;rsquo;t concern us much, as we lazily take the results out of the state machine, and even if we were to process an extreme amount of steps, the stack would not overflow.
The memory footprint would also not be that big unless we retained the head of the produced list somewhere.&lt;/p&gt;
&lt;p&gt;Now, onto mutual recursion.
Here are two more state machines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:play&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dog: runs back with a ball&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:throw&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;kid: throws the ball&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ball&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ball&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dog: runs for the ball&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:play&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;kid: does nothing&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dog: stops playing&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hopefully it&amp;rsquo;s not too complicated.&lt;/p&gt;
&lt;p&gt;There are two communicating state machines the &lt;code&gt;dog&lt;/code&gt; and the &lt;code&gt;kid&lt;/code&gt;.
The &lt;code&gt;kid&lt;/code&gt; can &lt;code&gt;:throw&lt;/code&gt; the ball, and the dog can &lt;code&gt;:play&lt;/code&gt; which means that it brings the ball back to the kid asking to throw again.
As can be seen, there&amp;rsquo;s a mutual recursion going on, and there&amp;rsquo;s no state that will make these machines halt.
The &lt;code&gt;kid&lt;/code&gt; and the &lt;code&gt;dog&lt;/code&gt; are doomed to play til the end of time, and the StackOverflow won&amp;rsquo;t save them.
Thankfully, they&amp;rsquo;re lazy, so they won&amp;rsquo;t unless we check on them.&lt;/p&gt;
&lt;p&gt;Now, you may be wondering, apart from being able to specify many states upfront, what is the reason for having states as a sequence?
Most of the time we&amp;rsquo;re just consing a new state, and discarding the previous one, so we could just use a singular state instead.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s right, but lazy sequences also give us one more advantage - such state machines can influence its future!&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s introduce a random chance for the &lt;code&gt;dog&lt;/code&gt; to get tired:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ball&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dog: runs for the ball&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rand&lt;/span&gt;) 0.75)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lazy-cat &lt;/span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:tired&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rest&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:play&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:rest&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dog: rests&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:tired&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;dog: walks back with a ball&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:tired&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;state&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;kid: sees dog is tired&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, we&amp;rsquo;ve changed the &lt;code&gt;:ball&lt;/code&gt; state for the &lt;code&gt;dog&lt;/code&gt;.
If the random number is higher than &lt;code&gt;0.75&lt;/code&gt;, the &lt;code&gt;dog&lt;/code&gt; changes its state to &lt;code&gt;:tired&lt;/code&gt; and appends a task for later to &lt;code&gt;:rest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, in the &lt;code&gt;:tired&lt;/code&gt; state, the &lt;code&gt;dog&lt;/code&gt; doesn&amp;rsquo;t want to do anything yet, so it looks at the &lt;code&gt;kid&lt;/code&gt; with the same &lt;code&gt;:tired&lt;/code&gt; state.
The &lt;code&gt;kid&lt;/code&gt; notices that the &lt;code&gt;dog&lt;/code&gt; is tired, and stops playing, allowing &lt;code&gt;dog&lt;/code&gt; to check if it wants to do anything else.
Earlier the &lt;code&gt;dog&lt;/code&gt; appended the &lt;code&gt;:rest&lt;/code&gt; task, so it decides to rest, and let&amp;rsquo;s &lt;code&gt;kid&lt;/code&gt; check if it has any more tasks to do.&lt;/p&gt;
&lt;p&gt;Since no more states are present, both stop playing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run!&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:throw&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throws&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;back&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throws&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;walks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;back&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sees&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;does&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nothing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stops&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;playing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the kid is extremely unlucky, this machine can still loop forever though.&lt;/p&gt;
&lt;p&gt;We can, however, force the &lt;code&gt;dog&lt;/code&gt; to play, by giving the kid two throwing tasks.
This would require implementing a &lt;code&gt;:default&lt;/code&gt; method for the &lt;code&gt;dog&lt;/code&gt;, so if it doesn&amp;rsquo;t know what to do with the state, it asks the &lt;code&gt;kid&lt;/code&gt; to check if it can.
The same applies to the &lt;code&gt;kid&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:default&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:default&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;states&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can make the kid more ignorant:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-state-machines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run!&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:throw&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throws&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;walks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;back&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sees&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throws&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;back&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throws&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;back&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throws&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runs&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;walks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;back&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ball&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sees&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kid&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;does&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nothing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dog&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stops&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;playing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The dog needs double rest now though.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s it!
I hope you&amp;rsquo;ve found this entertaining, and it would be cool to hear from you if you have ever used this kind of lazy state machine in the past, or if you can think of other cool applications for them.
Thank you for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Lazy state machines&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 15 May 2024 04:26:00 +0300</pubDate>
    </item><item>
      <title>Hobbies</title>
      <link>https://andreyor.st/posts/2024-04-02-hobbies/</link>
      <guid>https://andreyor.st/posts/2024-04-02-hobbies/</guid>
      <description>&lt;p&gt;For quite a long time programming was my main hobby.
I enjoyed it, as I felt like I was creating something (hopefully) useful, and the problems I tried to solve were making my brain-cogs turn.
However, recently it seemed to change, or at least, I&amp;rsquo;m feeling my &lt;em&gt;usual&lt;/em&gt; burnout a bit harder than usual.&lt;/p&gt;
&lt;p&gt;You may remember, recently I made a (now unlisted) post about taking a break from writing and thinking about what I want to do in the future with this blog.
Most of the stuff there is still relevant, though I felt that the way I put it down was a bit off my usual style, so I unlisted it.
This post is, somewhat, of a correction of these thoughts.&lt;/p&gt;
&lt;p&gt;Not so long ago I had a change in my career.
I&amp;rsquo;m still a software engineer, though now I will probably write less code, as I&amp;rsquo;m becoming a software architect.
This has a lot of implications, because I have to learn a lot of new stuff, and my work now consists of lots and lots of thinking on all levels.
It also means that the way I&amp;rsquo;m thinking has to change.&lt;/p&gt;
&lt;p&gt;My programming, usually, consisted of throwing my brain against a problem and seeing what sticks.
Rarely did I dig into the internals of stuff I was doing, research any prior art, or use known methodologies.
It was fun, but it is not the proper way of doing things unless you&amp;rsquo;re working on something completely new.
I used to think about it as my way of learning things, but honestly, it was more of a way to procrastinate.&lt;/p&gt;
&lt;p&gt;After reading a few books on how to think properly, I decided that I needed to change the approach.&lt;/p&gt;
&lt;p&gt;This resulted in an unusual amount of burnout in the last month, because now I have to think more about how things are done properly, and I have enough of it at work.
My mental capacity is not as huge as it may seem, so after-work programming sessions started to feel like a burden, rather than fun activities.
Well, for now at least.&lt;/p&gt;
&lt;p&gt;So I decided that I should switch my hobbies from computers for a while.
I&amp;rsquo;m now re-learning how to play guitar, and I finally went to the rock climbing gym.
Gotta say, that these activities are as brain-intense as programming, or at least they feel like it.
Though, I&amp;rsquo;m not sure if this blog is a fitting place to talk about both of these activities.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m still not giving up hope on gamedev though, so maybe after I&amp;rsquo;m more proficient with my current tasks I&amp;rsquo;ll return to programming, but I still think that I should limit my scope to one thing.
Gamedev looks like the most fun one - I have enough data-processing tasks at work, so something interactive is more encouraging.
Anyway, we&amp;rsquo;ll see.
Maybe instead I&amp;rsquo;ll become a &lt;em&gt;rock-climbing rock star&lt;/em&gt;, who knows?&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Hobbies&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 02 Apr 2024 21:59:00 +0300</pubDate>
    </item><item>
      <title>Accepting your own solutions to your own problems</title>
      <link>https://andreyor.st/posts/2024-03-05-accepting-your-own-solutions-to-your-own-problems/</link>
      <guid>https://andreyor.st/posts/2024-03-05-accepting-your-own-solutions-to-your-own-problems/</guid>
      <description>&lt;p&gt;There was a weird thought going over and over in my head, regarding my Emacs configuration, and it extends to the other projects I do both at home and at work.
You see, my configuration is riddled with custom code, and up until recently I had mixed feelings about that.&lt;/p&gt;
&lt;p&gt;For example, I have a custom piece of code to automatically switch themes, based on the dark mode setting in my desktop environment.
I do so via the DBUS interface:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;featurep&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;dbusbind&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:requires&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;functions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local-config&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbus-register-signal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbus-call-method&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color-scheme-changed&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;DBus handler to detect when the color-scheme has changed.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-equal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;org.freedesktop.appearance&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-equal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;color-scheme&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;equal&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;load-theme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local-config-dark-theme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;load-theme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;local-config-light-theme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbus-color-theme-dark-p&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;equal&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;1&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;caar&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbus-call-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:session&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;org.freedesktop.portal.Desktop&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/org/freedesktop/portal/desktop&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;org.freedesktop.portal.Settings&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Read&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;org.freedesktop.appearance&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;color-scheme&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (error &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbus-register-signal&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:session&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;org.freedesktop.portal.Desktop&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/org/freedesktop/portal/desktop&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;org.freedesktop.portal.Settings&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;SettingChanged&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color-scheme-changed&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works perfectly fine for me, yet there&amp;rsquo;s a certain feeling I experience every time I see it in my configuration.&lt;/p&gt;
&lt;p&gt;Or, here&amp;rsquo;s another example, that kinda motivated me to write this post.&lt;/p&gt;
&lt;p&gt;With the introduction of Tree-Sitter, Emacs now can use different parsers to provide syntax highlighting for certain modes.
I use it with several modes, but the default experience is a bit rough because while there are functions to install grammars, they&amp;rsquo;re a bit inconvenient for general use.
So to mitigate that, I made this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-p&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Check if Emacs was built with treesiter in a protable way.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fboundp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;treesit-available-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-available-p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cl-defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-install-and-remap&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;key&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;revision&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;modes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remap&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org-src&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Convenience function for installing and enabling a ts-* mode.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;LANG is the language symbol.  URL is the Git repository URL for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the grammar.  REVISION is the Git tag or branch of the desired
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;version, defaulting to the latest default branch.  SOURCE-DIR is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the relative subdirectory in the repository in which the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;grammar’s parser.c file resides, defaulting to \&amp;#34;src\&amp;#34;.  MODES is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;a list of modes to remap to a symbol REMAP.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fboundp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;treesit-available-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-available-p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-language-available-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;treesit-language-source-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;revision&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source-dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-install-language-grammar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remap&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-ready-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;modes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;major-mode-remap-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remap&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org-src&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-ready-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-after-load&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;org&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;org-src-lang-modes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org-src&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-font-lock-level&lt;/span&gt; 2))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I use it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:defer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-install-and-remap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;javascript&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://github.com/tree-sitter/tree-sitter-javascript&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:revision&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;master&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:source-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:modes&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;javascript-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js2-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:remap&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;js-ts-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:org-src&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;js&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js-ts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json-ts-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:defer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-install-and-remap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;json&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://github.com/tree-sitter/tree-sitter-json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:modes&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js-json-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:remap&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;json-ts-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:org-src&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;json-ts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elixir-ts-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:defer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;treesit-install-and-remap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;elixir&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://github.com/elixir-lang/tree-sitter-elixir&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:org-src&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;elixir&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elixir-ts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, this function handles everything from installing the grammar to remapping the major modes to use tree-sitter-backed ones, and also handles Org Mode source block languages.&lt;/p&gt;
&lt;p&gt;Finally, I have these packages, that I made over the years of using Emacs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:vc&lt;/span&gt; ( &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/isayt.el.git&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:branch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:rev&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:newest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:delight&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:vc&lt;/span&gt; ( &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/region-bindings.el.git&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:branch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:rev&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:newest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings-off&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings-mode&lt;/span&gt; -1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;after-init&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;global-region-bindings-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elfeed-search-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;magit-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mu4e-headers-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings-off&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;isayt&lt;/code&gt; package automatically keeps the lisp code indented as I type, and the &lt;code&gt;region-bindings&lt;/code&gt; package enables mappings while the region is active.
Originally both these packages were just a part of my configuration, but the amount of code became a bit too big for my liking so I moved them into separate files, and uploaded them to GitLab.&lt;/p&gt;
&lt;p&gt;Now, why am I telling you all this, you might ask, and what it has to do with the title of this post?&lt;/p&gt;
&lt;p&gt;Well, you see, each example that I have shown you has a package that already does something like that.&lt;/p&gt;
&lt;p&gt;The DBUS theme switching is handled by the &lt;a href=&#34;https://github.com/LionyxML/auto-dark-emacs&#34; target=&#34;_blank&#34;&gt;auto-dark-emacs&lt;/a&gt; package, however, it also handles macOS, Termux, and Windows, while I only support my operating system of choice.
Tree-Sitter is handled by the &lt;a href=&#34;https://github.com/renzmann/treesit-auto&#34; target=&#34;_blank&#34;&gt;treesit-auto&lt;/a&gt; package, which covers much more languages than I am.
For automatic indentation, there&amp;rsquo;s the &lt;a href=&#34;https://github.com/Malabarba/aggressive-indent-mode&#34; target=&#34;_blank&#34;&gt;aggressive-indent-mode&lt;/a&gt; which, unlike &lt;code&gt;isayt&lt;/code&gt;, handles not only lisps, but other language modes as well.
And the &lt;code&gt;region-bindings&lt;/code&gt; package is basically a reimplementation of the &lt;a href=&#34;https://github.com/fgallina/region-bindings-mode&#34; target=&#34;_blank&#34;&gt;region-bindings-mode&lt;/a&gt; package.&lt;/p&gt;
&lt;p&gt;So why did I create all these things, even if there are solutions already available and used by the community?&lt;/p&gt;
&lt;p&gt;Well, I created &lt;code&gt;isayt&lt;/code&gt; because I wasn&amp;rsquo;t satisfied with the timer-based approach of &lt;code&gt;aggressive-indent-mode&lt;/code&gt;.
It felt laggy.
Moreover, I don&amp;rsquo;t really need this in any modes other than lisps.
Lisp is structured, and indentation is semantic, so having it automatically adjust is nice.
Other languages either can&amp;rsquo;t do that properly, while having semantic indentation (e.g. Python) or don&amp;rsquo;t really need it, because there&amp;rsquo;s no real benefit to having your code always shift around, as it doesn&amp;rsquo;t really represent a data structure.&lt;/p&gt;
&lt;p&gt;I made &lt;code&gt;region-bindings&lt;/code&gt; because the original &lt;code&gt;region-bindings-mode&lt;/code&gt; didn&amp;rsquo;t work properly with turned off &lt;code&gt;transient-mark-mode&lt;/code&gt; (TMM).
I don&amp;rsquo;t remember why I disabled it, perhaps after reading Mastering Emacs, or some other power-users note on how not having a visible region makes you more productive.
In the end, I enabled TMM back, but the package already performed with fewer bugs than the &lt;code&gt;region-bindings-mode&lt;/code&gt; so I decided to keep it.&lt;/p&gt;
&lt;p&gt;The DBUS stuff is simple, really.
At the time I wrote this code, I don&amp;rsquo;t think any packages did that.
Now, it works fine, and I don&amp;rsquo;t see any reason to replace it with a package from someone else.
It works, so don&amp;rsquo;t touch it.
Moreover, I haven&amp;rsquo;t changed this piece of code ever since I wrote it (except for that time when the API changed in GNOME), and the &lt;code&gt;auto-dark-mode&lt;/code&gt; is somehow constantly updated.&lt;/p&gt;
&lt;p&gt;Finally, I just don&amp;rsquo;t need support for all of the tree-sitter-based modes out there, so it&amp;rsquo;s fine for me to throw a small &lt;code&gt;use-package&lt;/code&gt; form with a single call to my custom function.&lt;/p&gt;
&lt;p&gt;There are many more examples of custom weird things I do in my configuration, like &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L1604-1658&#34; target=&#34;_blank&#34;&gt;custom compilation modes&lt;/a&gt; with &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L1664-1753&#34; target=&#34;_blank&#34;&gt;complicated filename handling&lt;/a&gt;.
Or the &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L1883-1917&#34; target=&#34;_blank&#34;&gt;mu4e context managing code&lt;/a&gt; based on some private data structures I defined to automate the process of adding new inboxes.
I have a &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L84-99&#34; target=&#34;_blank&#34;&gt;custom memoization macro&lt;/a&gt; and a piece of code that decides &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L301-345&#34; target=&#34;_blank&#34;&gt;if I can scroll my window to the left&lt;/a&gt;.
I wrote so much code for automating stuff for this very blog that I decided to move it into a &lt;a href=&#34;https://gitlab.com/andreyorst/blog.el&#34; target=&#34;_blank&#34;&gt;separate package&lt;/a&gt;.
Yet, there are still &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L56-75&#34; target=&#34;_blank&#34;&gt;pieces&lt;/a&gt; spread &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L889-907&#34; target=&#34;_blank&#34;&gt;across&lt;/a&gt; my &lt;code&gt;init.el&lt;/code&gt; that are &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L909-931&#34; target=&#34;_blank&#34;&gt;related&lt;/a&gt; to my blog &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/14e8960587d16f352184eded8d264cb93f414e6e/.config/emacs/init.el#L933-946&#34; target=&#34;_blank&#34;&gt;workflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have a lot of custom code that is oriented to solve &lt;strong&gt;my&lt;/strong&gt; problems and enhance &lt;strong&gt;my&lt;/strong&gt; editing experience.
After years, I learned to accept this kind of philosophy in programming - if you can solve your problem, and learn something new along the way, then &lt;strong&gt;do it&lt;/strong&gt;.
It doesn&amp;rsquo;t matter if the solution already exists.
More often than not I&amp;rsquo;m frustrated with small annoyances of how many packages kinda do what I want, but also not exactly how I&amp;rsquo;d like to.&lt;/p&gt;
&lt;p&gt;This also affected how I think about code in general.
When faced with a problem I don&amp;rsquo;t want to reach to a library until I see that implementing a solution is either pointless, too complicated, and error-prone, or if I don&amp;rsquo;t have time to do that.
Only then do I go and look for a library.
I guess, I&amp;rsquo;m lucky to code in Clojure at work, as the language has a lot of useful features, making it often unnecessary to search for a library to do something.
In other languages, the situation may be different.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s kinda the same in Emacs - the core has so much stuff that most of the time you don&amp;rsquo;t need any extra packages.
You just have to dig a bit, and you&amp;rsquo;ll probably find a function that solves your problem.
Or can help you solve it.&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s code is often complicated, and this complexity is justified by achieving so-called &amp;ldquo;reuse&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This library is so general that you can reuse it in your very specific context!
This code is so abstract that it is basically an art form!&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t buy that anymore.
The most reusable code is the one you can copy from one project and paste into another one, and just use it.
Of course, copy-pasting is just a metaphor, we create a library with that code and use it in different projects.
But the code in that library could as well just be copied, meaning there were no changes to that code to make it support multiple scenarios.
And if you have to support multiple scenarios - just modify this code!&lt;/p&gt;
&lt;p&gt;That was a bit of a tangent, but I feel that it applies to what I do in my Emacs configuration.
A lot of Emacs packages are way too complicated because they have to support very specific cases that the author of a package might not even have.
We became too afraid to take a piece of code and modify it to our needs ourselves.
And Emacs actually gives you tools to do that - the hooks, and the advice system.
I advice a lot of stuff in my Emacs configuration, and I&amp;rsquo;m glad that this system is there and that it works in such a robust way that it allows me to do crazy stuff without fear that it&amp;rsquo;ll break.
And if it breaks, I&amp;rsquo;ll just fix it.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a fine solution.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Accepting your own solutions to your own problems&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 05 Mar 2024 03:42:00 +0300</pubDate>
    </item><item>
      <title>Programming languages are stuck in the 80s</title>
      <link>https://andreyor.st/posts/2024-03-01-programming-languages-are-stuck-in-the-80s/</link>
      <guid>https://andreyor.st/posts/2024-03-01-programming-languages-are-stuck-in-the-80s/</guid>
      <description>&lt;p&gt;Maybe I&amp;rsquo;m &amp;ldquo;beating a dead horse&amp;rdquo; here, but I haven&amp;rsquo;t thought about programming languages in this particular way before, so I decided to share the thought anyway:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Most programming languages I know are designed like it&amp;rsquo;s still 80&amp;rsquo;s, and all we have are textual interfaces, and single-core CPUs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, the last part isn&amp;rsquo;t entirely correct so to speak - many languages have support for multithreading, it&amp;rsquo;s just the fact that they often still list it as a &lt;em&gt;feature&lt;/em&gt; even though we have multi-core CPUs in the home segment for 25 years now.
And even if the support for parallelization is present, you often have to go out of your way to use it.
Moreover, we now have GPU computing, and a lot of stuff gets computed on GPUs today, but how many programming languages have native support for that in their standard library?
Even if not for GPU computing, how many languages do you know that have a way to display a window without relying on an external library that basically contains bindings to some toolkit written in C?&lt;/p&gt;
&lt;p&gt;Look, Java, despite all the hate, can create a window with AWT.
You might still wonder, why am I saying this like it&amp;rsquo;s something special?
Well, because if you look at most other languages&amp;rsquo; standard libraries, you&amp;rsquo;ll see that even if they have a lot of useful stuff, like networking, OS stuff, etc - it&amp;rsquo;s really nothing special as of today.
All this stuff is there and has been there since the 80s.
Except, some languages from the 80s still have more features.&lt;/p&gt;
&lt;p&gt;I know, more languages have GUI facilities.
Microsoft&amp;rsquo;s C# has facilities for GUI programming for the Windows operating system.
Apple&amp;rsquo;s Swift has SwiftUI, which is one of the main ways to do GUI for Apple products.
I guess Kotlin has Compose, and there&amp;rsquo;s Dart with Flutter, but I have mixed feelings about these platforms, so I&amp;rsquo;ll not delve into them.
Linux&amp;hellip; we&amp;rsquo;ll get to that.&lt;/p&gt;
&lt;p&gt;Notice how both C# and Swift are basically platform-specific?
It would be strange for these languages &lt;strong&gt;not to have&lt;/strong&gt; a GUI library of sorts, because if the vendor language doesn&amp;rsquo;t provide you with one how else would you do GUI for that system?
Similar thing with Kotlin and Flutter but they&amp;rsquo;re more phone-oriented, and the situation there is a bit different than on the desktop.&lt;/p&gt;
&lt;p&gt;Well, C programmers have written multiple toolkits, like GTK, and C++ programmers have Qt, which looks decent, but then, these are not part of the language.
And for Linux, this means that there&amp;rsquo;s no central way to do GUI - the most popular choices are GTK and Qt, but if you choose GTK you&amp;rsquo;ll have poor integration with Qt-based desktops, and vice versa.
In simpler cases, you can use something like SDL, and just create a window, and then draw anything you want.
It&amp;rsquo;s a shame though, that this isn&amp;rsquo;t just available in the language.
A language that is being used for both writing a kernel, the userspace, and the GUI running in that userspace - the language itself doesn&amp;rsquo;t have the means to create a simple window.
I mean, there&amp;rsquo;s &lt;a href=&#34;https://vala.dev/&#34; target=&#34;_blank&#34;&gt;Vala&lt;/a&gt;, but c&amp;rsquo;mon.&lt;/p&gt;
&lt;p&gt;Nowadays, Rust people, whose main focus is to rewrite everything in their language of choice &lt;sup&gt;(what language is it, btw?)&lt;/sup&gt;, are reinventing GUI toolkits all over again.
Why doesn&amp;rsquo;t Rust have its own GUI library that supports all of the major operating systems?
Especially given the origin of Rust is a web browser - in other words, rendering graphics should be pretty natural to Rust.
Can a language really call itself modern without an inbuilt GUI library, in a world where everything runs with some kind of GUI?&lt;/p&gt;
&lt;p&gt;The same goes for pretty much any other language that calls itself &amp;ldquo;modern&amp;rdquo; - you can call yourself that all you want, but if you can&amp;rsquo;t do something that most languages from the &amp;rsquo;80s could, then define &amp;ldquo;modern&amp;rdquo;.
And don&amp;rsquo;t come to me with all this &amp;ldquo;modern approach to programming&amp;rdquo; - garbage-collected bytecode interpreter isn&amp;rsquo;t modern.
If you have a JIT and state-of-the-art GC algorithm, your VM is highly dynamic and modifiable, we can talk, but then again - does your language provide anything more than the other ones apart from subjectively nicer syntax and opinionated standard library?
Pretty much all new languages are toy projects - rare few really do bring new things to the table, and deserve being called modern.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s an amazing talk, which I realized contains mostly everything I wanted to say in this post but in a better form: &lt;a href=&#34;https://www.youtube.com/watch?v=8Ab3ArE8W3s&#34; target=&#34;_blank&#34;&gt;Stop Writing Dead Programs&lt;/a&gt;.
I do recommend watching it and trying out the technologies mentioned in the talk.
Many of these had a major influence on how I see most languages these days.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s get back to GUI&amp;rsquo;s for a bit - what&amp;rsquo;s funny, actual languages from the 80&amp;rsquo;s didn&amp;rsquo;t have this problem.&lt;/p&gt;
&lt;p&gt;Take for example Smalltalk - it had a lot of GUI capabilities pretty much since it was developed.
Remember Xerox?
They had Smalltalk with a GUI interface running on Xerox Alto in 1979!
Since then we had all kinds of GUI systems available, yet so few languages took advantage of that.&lt;/p&gt;
&lt;p&gt;Symbolics had Lisp Machines running GUI in the 80&amp;rsquo;s.
Lisp itself was about 20 years old by that time, yet it got GUI support pretty much instantly everyone started doing GUI!
After a bit of digging, I found that MIT Scheme had graphics support at least since 1995, but definitively since even earlier - I just couldn&amp;rsquo;t find any documents before version 7.3 to confirm.
But I&amp;rsquo;m sure of it because it was used in the SICP book, and its first edition had the graphics programming section in it since the 1980s.
Racket, one of the modern Schemes, has a GUI programming library bundled with the language, if you choose so.
And it supports all major operating systems.&lt;/p&gt;
&lt;p&gt;Tcl is yet another example.
It&amp;rsquo;s from the 90s, but it also had GUI programming capabilities via the Tk toolkit since 1991.&lt;/p&gt;
&lt;p&gt;I mean, sure - it&amp;rsquo;s obvious now why command line utilities, and TUI libraries are still &lt;em&gt;hot&lt;/em&gt; even today, in 2024!
Because most languages only know how to talk to standard out!
Then we have curses, various TUI toolkits written in Rust or Go of all things, and still using an emulator for VT100 - a piece of tech from 1978.
I guess, targeting VT100 is easier, than targeting some specific toolkit/window manager/display server/whatever, yet some languages manage somehow?&lt;/p&gt;
&lt;p&gt;And today you don&amp;rsquo;t have to do even that - we have cross-platform browsers that run everywhere.
Take JavaScript - another language many people openly hate.
Yes, it has quirks in the design, and yes it has performance issues, yet we use it every day because it can draw on the screen in the browser!
And visuals are the main way we perceive the world &lt;sup&gt;&lt;sup&gt;&lt;sup&gt;Wide Web&lt;/sup&gt;&lt;/sup&gt;&lt;/sup&gt;.
And a lot of people I know, fell in love with programming because they can actually &lt;strong&gt;see&lt;/strong&gt; the results of their code immediately!&lt;/p&gt;
&lt;p&gt;People realized that we had such poor options for GUI programming with all these system languages, GUI toolkits, static types, yada yada, and made Electron.
Kudos to them, now we can build GUIs in JavaScript, without relying on any particular toolkit for better or worse.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have any false beliefs in browsers being a proper way to do this kind of stuff - if anything, I want a web browser to be a simple thing.
A &lt;strong&gt;web&lt;/strong&gt; &lt;strong&gt;browser&lt;/strong&gt;.
Not another glorified VT100 that, instead of parsing escape codes, parses JavaScript.
I don&amp;rsquo;t want to run software in a browser.
If you need a cross-platform way to write apps with facilities similar to what the current state of the web provides - use something other than the browser.
Even Electron would be a better fit.&lt;/p&gt;
&lt;p&gt;I know, I know, Electron is just stripped down &lt;sup&gt;(maybe not)&lt;/sup&gt; Chromium, but I still think it&amp;rsquo;s better than running in a browser because it&amp;rsquo;s still a separate thing.
Browsers have a specific workflow built in, and when the app tries to override it, it always works horribly (think shortcuts).
Recently, with the introduction of WebAssembly and WebGPU now we have the option to draw something in the browser using other languages than JavaScript, and maybe even with more performance.
Maybe in a few years, we&amp;rsquo;ll get something slimmer than Electron, with a better dynamic language that will utilize WA, and thus will become the next application platform.
Though I don&amp;rsquo;t want to be too optimistic.&lt;/p&gt;
&lt;p&gt;Speaking of application platforms, Emacs is one such application platform, again from the 80s.
Look at it this way, Emacs has a runtime with GC and compilation to machine code, some GUI capabilities, and a language that can change how Emacs works almost without any limits.
People have been writing applications for Emacs for many years now.&lt;/p&gt;
&lt;p&gt;Like browsers, Emacs runs on multiple systems, and applications developed for Emacs run on different systems, if you don&amp;rsquo;t use platform-specific stuff too much.
However, Emacs can&amp;rsquo;t really compete with browsers in terms of user interactivity.
Well, you can have interactive stuff, it&amp;rsquo;s just janky.
If you see someone saying things like Org Mode is basically Jupiter Notebook on steroids - ask them to create sliders in Org Mode that dynamically update variables in a code that is then plotted in 3D in real-time.
You can do 3D plots in Org Mode, sure, interacting with 3D plots is the problem.&lt;/p&gt;
&lt;p&gt;I mean, I&amp;rsquo;m glad I can plot the data and display the graph as an inline image in the REPL while working on some project, but &lt;a href=&#34;https://www.youtube.com/watch?v=EGqwXt90ZqA&#34; target=&#34;_blank&#34;&gt;can we have this instead&lt;/a&gt;?
I&amp;rsquo;d like to see projects like &lt;a href=&#34;https://gtoolkit.com/&#34; target=&#34;_blank&#34;&gt;Glamorous Toolkit&lt;/a&gt; for more languages.
Now, that&amp;rsquo;s modern.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve spent a major part of this post talking about GUI specifically because, well, all of my devices have a GUI, yet I can&amp;rsquo;t pick a language and draw a window with it.
Recently I made a post &lt;a href=&#34;https://andreyor.st/posts/2023-07-11-emacs-gui-library/&#34;&gt;speculating how Emacs could get a GUI library&lt;/a&gt;, and while I understand that this is ambitious, I still think having a decent GUI library and arbitrary drawing capabilities as a part of the language can make a great application platform.&lt;/p&gt;
&lt;p&gt;OK, &lt;strong&gt;I understand&lt;/strong&gt;, that making something good with these in-house GUI libraries is often a daunting task.
Most Java AWT apps I&amp;rsquo;ve used look horrible.
Same for JavaFX, Swing, etc.
C# kinda can make a decently looking app, if decent means looking like all other Windows apps in your book.
And other GUI libraries, that try to mimic OS GUI guidelines, like Racket&amp;rsquo;s library are fine, but you can&amp;rsquo;t really make an appealing app with that either, because you do want to design an app for each respective system, follow their guidelines, and so on.
Not only that - OS GUIs are getting worse by the year too.
And I think desktop OS GUIs are getting worse partly because of advancements in mobile GUIs.&lt;/p&gt;
&lt;p&gt;The smartphone industry gave another shake to GUI programming because it is a different medium with different control schemes, and thus we have new ways to do GUI.
And platform languages, as I mentioned, have decent GUI programming support.
Yet, people still often just want to bring something like React Native, because it is easier to make an interface in it, and ship it to all platforms, instead of developing several GUIs.
So we have the Electron situation &lt;em&gt;on our hands&lt;/em&gt; all over again.&lt;/p&gt;
&lt;p&gt;But I don&amp;rsquo;t want you to think that I believe that GUI is the only thing that makes a language modern - no, of course not.
Just, let&amp;rsquo;s put it this way - go and research a bit of programming language history, and you&amp;rsquo;ll probably find a lot of interesting things.
Like the fact, that JIT compilation was a thing in APL of all things &lt;a href=&#34;https://www.softwarepreservation.org/projects/apl/Papers/DYNAMICINCREMENTAL&#34; target=&#34;_blank&#34;&gt;in 1979&lt;/a&gt;.
Forty-five years ago.&lt;/p&gt;
&lt;p&gt;Anyway, what I wanted to say with this post is simple.
We already have 65+ years of programming language history, yet, most new languages seem to completely ignore most of it, repeating what&amp;rsquo;s been done in the earliest years, calling it modern.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Programming languages are stuck in the 80s&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 01 Mar 2024 23:20:00 +0300</pubDate>
    </item><item>
      <title>Using transducers</title>
      <link>https://andreyor.st/posts/2024-01-31-using-transducers/</link>
      <guid>https://andreyor.st/posts/2024-01-31-using-transducers/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been working with Clojure professionally for four years now, and I made some posts about the language in the past.
Clojure is a great language, although not without its fair share of things to consider.
In other words, I don&amp;rsquo;t see Clojure as an ideal language by any means, and it&amp;rsquo;s not suitable for every type of project.
Still, the language is my favorite among others, and I enjoy writing and reading code in it.&lt;/p&gt;
&lt;p&gt;Now, I already made a post about &lt;a href=&#34;https://andreyor.st/posts/2022-08-13-understanding-transducers/&#34;&gt;transducers&lt;/a&gt; before.
In that post I tried to explain what transducers are, how they work, and more importantly how they compose.
I think since then I had a good grasp on what transducers are, and I use them when appropriate.
However, I still see some concerns when it comes to transducers in the community, even though I&amp;rsquo;m almost not involved in it, and I see this even at work sometimes.
So, this post isn&amp;rsquo;t going to be hard on the technical details behind transducers, but more about how and when you should use them.&lt;/p&gt;
&lt;h2 id=&#34;don-t-be-lazy-until-it-matters&#34;&gt;Don&amp;rsquo;t be lazy until it matters&lt;/h2&gt;
&lt;p&gt;Clojure has a weird aspect to it that trips a lot of people - Clojure is lazy by default.
Often I see this kind of code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.string/join&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;separator&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is just an example, of course, but the pattern is not uncommon - we build a sequence and consume it.
Ideally, though this code should use &lt;code&gt;mapv&lt;/code&gt; instead of &lt;code&gt;map&lt;/code&gt; because &lt;code&gt;map&lt;/code&gt; is lazy.
Lazy sequences in Clojure come with a bit of overhead, and in this case we&amp;rsquo;ll be consuming everything immediately, thus this overhead is not justified.
I&amp;rsquo;ll admit, this particular example can  benefit from consuming a lazy sequence, if the sequence is large enough.
This will ensure that we don&amp;rsquo;t store both the string and the sequence itself in the memory, only the string and one of the elements of the sequence.
Often, however, programmers just type out &lt;code&gt;map&lt;/code&gt; because it&amp;rsquo;s a common concept, not thinking about it being lazy, and whether if the laziness here is beneficial or not.
Now, that&amp;rsquo;s not about transducers, really, but it&amp;rsquo;ll make sense in a few minutes why I bring this up.&lt;/p&gt;
&lt;h3 id=&#34;the-spear-of-lazy-poisoning&#34;&gt;The spear of lazy poisoning&lt;/h3&gt;
&lt;p&gt;Clojure has a lot of convenience features in its core library, and I think that&amp;rsquo;s partly the reason why people, myself included, like the language.
One of such conveniences are &lt;code&gt;-&amp;gt;&lt;/code&gt; and &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; macros.
These are hard to understand at first, but once you get what they do, I think it&amp;rsquo;s a safe bet that you&amp;rsquo;ll going to use them pretty much everywhere.
It makes the code easier to read.
Now, these macros don&amp;rsquo;t do anything crazy, they just make deeply nested expressions appear unnested.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s an expression that maps over the range of ten numbers, incrementing everything, filtering odd numbers, and adding them together:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce + &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map inc &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice how the expression is written pretty much backward from what I&amp;rsquo;ve described.
First comes &lt;code&gt;reduce&lt;/code&gt;, then &lt;code&gt;filter&lt;/code&gt;, then &lt;code&gt;map&lt;/code&gt;, and, finally, &lt;code&gt;range&lt;/code&gt;.
Lisps are known for this kind of notation, and you often read the code backward.
In a more mainstream language, this would probably have been written like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[0,1,2,3,4,5,6,7,8,9].map(x=&amp;gt;x+1).filter(x=&amp;gt;x%2!=0).reduce((res,x)=&amp;gt;res+x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, the order of operations feels more logical, even though it&amp;rsquo;s just a syntactic abstraction.
Methods, really, are just functions, and their first argument simply is what appeared before the dot.
In its essence, the above code is equivalent to this code, even though it&amp;rsquo;s not a valid JavaScript:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reduce(filter(map([0,1,2,3,4,5,6,7,8,9], x=&amp;gt;x+1), x=&amp;gt;x%2!=0), (res,x)=&amp;gt;res+x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we&amp;rsquo;re back to the start, &lt;code&gt;reduce&lt;/code&gt; is executed last, but appears first.
The &lt;code&gt;.&lt;/code&gt; allows us to express this more sequentially, and that&amp;rsquo;s what Clojure&amp;rsquo;s &lt;code&gt;-&amp;gt;&lt;/code&gt; and &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; are for.
The original code can be rewritten as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The difference between &lt;code&gt;-&amp;gt;&lt;/code&gt; and &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; is only where the previous expression is going to be placed in the next expression.
The thread-first (&lt;code&gt;-&amp;gt;&lt;/code&gt; )puts it as the first argument, and thread-last (&lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt;) as the last: &lt;code&gt;(-&amp;gt; 42 (+ 1 2))&lt;/code&gt; expands to &lt;code&gt;(+ 42 1 2)&lt;/code&gt; and &lt;code&gt;(-&amp;gt;&amp;gt; 42 (+ 1 2))&lt;/code&gt; expands to &lt;code&gt;(+ 1 2 42)&lt;/code&gt;.
This repeats for all forms in the threading macro.
Now, that was a pretty long tangent, but I felt that this needs explaining, because we&amp;rsquo;re going to see the use of &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; in the following examples.&lt;/p&gt;
&lt;p&gt;Why did I call this section &amp;ldquo;The spear of lazy poisoning&amp;rdquo;?
Well, I think that &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; looks like a spear, or a harpoon, and it often poisons the code with unnecessary laziness.
You can even see that in the example above - both &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; are lazy, yet the &lt;code&gt;reduce&lt;/code&gt; is eager, and all laziness up to that point was unnecessary because the data we were processing is finite.
This gives us the laziness overhead, which is mostly computational.
We can, of course, use &lt;code&gt;mapv&lt;/code&gt; and &lt;code&gt;filterv&lt;/code&gt; - the eager versions of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; that produce vectors instead, but it would also harm us:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filterv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we construct a whole vector only to discard half of it in the next step, then discarding the remaining half in the &lt;code&gt;reduce&lt;/code&gt;.
That&amp;rsquo;s a memory overhead we&amp;rsquo;d also like to avoid.
So what should we do?&lt;/p&gt;
&lt;h2 id=&#34;transducers&#34;&gt;Transducers&lt;/h2&gt;
&lt;p&gt;Transducers are used by the &lt;code&gt;transduce&lt;/code&gt; function which is like &lt;code&gt;reduce&lt;/code&gt; except it doesn&amp;rsquo;t accept just a reducing function, it also accepts a transforming function.
Before we go into that, let&amp;rsquo;s go back to the lazy example for a moment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I think it&amp;rsquo;s important to build intuition of how it works.&lt;/p&gt;
&lt;p&gt;The operations are lazy, so by the time we get to the &lt;code&gt;reduce&lt;/code&gt;, nothing happened yet.
What we get in the &lt;code&gt;reduce&lt;/code&gt; is a lazy composition of two operations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take one item from the range sequence, and process it with &lt;code&gt;inc&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Take one item from sequence built by &lt;code&gt;map&lt;/code&gt;, filter it with &lt;code&gt;odd?&lt;/code&gt;;
a. If the result is not truthly, go to step 1;&lt;/li&gt;
&lt;li&gt;Reduce it to the result using &lt;code&gt;+&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means that in reality, the sequence that the &lt;code&gt;reduce&lt;/code&gt; is processing looks kinda like &lt;code&gt;[(odd? (inc 0)), (odd? (inc 1)), (odd (inc 2)), ...]&lt;/code&gt;, with the exception that filtered items magically disappear from it.
These expressions are lazy, and not computed until they get into &lt;code&gt;reduce&lt;/code&gt; which realizes them.
This, of course, isn&amp;rsquo;t how it works, but you can use this model for building intuition.&lt;/p&gt;
&lt;p&gt;If you want to read more about lazy sequences, I have a &lt;a href=&#34;https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/&#34;&gt;post&lt;/a&gt;, describing the implementation of a simple lazy sequence.
It&amp;rsquo;s in Lua, but the code should be simple enough to understand even if you don&amp;rsquo;t know the language.&lt;/p&gt;
&lt;p&gt;Now, the key part here is that we&amp;rsquo;re composing operations by delaying them - we could say that we&amp;rsquo;re building a recipe.
However, each operation is lazy, but, as you can see, we don&amp;rsquo;t need every operation to be lazy, as once we get a number we can process it eagerly from there.
In other words, if we could combine both &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; into a single step, we could avoid the overhead of multiple lazy compositions.&lt;/p&gt;
&lt;p&gt;Now, Clojure has such a function, it&amp;rsquo;s called &lt;code&gt;keep&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;keep&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, &lt;code&gt;keep&lt;/code&gt; is also lazy, and in this case, again, there&amp;rsquo;s no point in being lazy.
And we may need to work with something more general, i.e. not always want to combine &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;, sometimes we need to combine multiple &lt;code&gt;map&lt;/code&gt; calls, or even some other things, like partitioning.
That&amp;rsquo;s where transducers come in nicely.&lt;/p&gt;
&lt;p&gt;Clojure developers actually wanted to solve a different problem when they introduced transducers, and I&amp;rsquo;ll get to it a bit later.
For now, we can rewrite our code to be both eager and memory-efficient:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just kidding.
That&amp;rsquo;s a lot of machinery for describing the core concepts of the language.
Here&amp;rsquo;s how to do it with &lt;code&gt;transduce&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it is different from &lt;code&gt;reduce&lt;/code&gt; because both &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; are not involved with the collection processing at all.
Instead, they go as a parameter to the &lt;code&gt;transduce&lt;/code&gt; function, and we use &lt;code&gt;comp&lt;/code&gt; to compose the two into a single step that does everything.
Importantly, both &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; calls are made without any collection supplied to them - this way these functions return transducers.
I tried my best &lt;a href=&#34;https://andreyor.st/posts/2022-08-13-understanding-transducers/#understanding-the-inverse-order-in-comp-and-how-transducers-are-composed&#34;&gt;explaining how transducer composition works&lt;/a&gt; in my previous post on the matter, so read it if you want to know.&lt;/p&gt;
&lt;p&gt;However, that&amp;rsquo;s a lot to take in, as transducers are quite involved, so here&amp;rsquo;s a simpler intuition for you.&lt;/p&gt;
&lt;p&gt;If you want to refactor any &lt;em&gt;transduceible&lt;/em&gt; expression into a transducer, first, transform it into the &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; form, and then replace the &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; with comp:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce + &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map inc &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; rewrite using -&amp;gt;&amp;gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; replace -&amp;gt;&amp;gt; with comp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re halfway through, though.
This code obviously wrong, but what&amp;rsquo;s left out to do is to understand what it does, and finish the transformation.
The first step is always the same though, we need to remove the data that we&amp;rsquo;re processing from this expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; just move it aside for now&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, &lt;code&gt;reduce&lt;/code&gt; isn&amp;rsquo;t &lt;em&gt;transduceible&lt;/em&gt;, so we need to move it out and replace it with something that can accept the transducer, like &lt;code&gt;transduce&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; with transduce we know where to put the data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s basically it.
You can apply this method to pretty much any &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; expression, as long as the calls done there have arities that return transducers.&lt;/p&gt;
&lt;h3 id=&#34;more-examples&#34;&gt;More examples&lt;/h3&gt;
&lt;p&gt;I know, the example above was weird, so here&amp;rsquo;s a different one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, we build a sequence of users who have the administrator role on the server and add some additional data while we&amp;rsquo;re at it.
We then &lt;code&gt;notify&lt;/code&gt; each such user.
This is not a real-world code, though I have seen something like that in production.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;notify&lt;/code&gt;, again, consumes all of the users, so we don&amp;rsquo;t really need the laziness, here, unless &lt;code&gt;get-users&lt;/code&gt; doesn&amp;rsquo;t return an infinite sequence of users, which it is not.
But even if it did, we don&amp;rsquo;t really need all of the steps to be lazy here, so we can go about this two ways.&lt;/p&gt;
&lt;p&gt;If the list of users is short, we can store it in a vector.
Let&amp;rsquo;s refactor the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; start with `comp`:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; move out data and consumer:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Since we want a vector, we can use `into`:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; let&amp;#39;s bring back -&amp;gt;&amp;gt; to bring nesting down a bit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we still want to consume users lazily, we can use &lt;code&gt;sequence&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; now the result is a lazy sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a small change from the previous example, but it has benefits over the original example.
In the original example, we had all processing done lazily, however, we only needed to consume users lazily, and the transformation can be done eagerly for each user.
We just don&amp;rsquo;t want to do the transformation in the &lt;code&gt;notify&lt;/code&gt; function, because it is not its task really.
The &lt;code&gt;sequence&lt;/code&gt; function consumes input lazily, applying a composed transformation to every element, and produces a lazy sequence as a result.
Thus we only have overhead of one lazy sequence, instead of four.
Your profiling flame graphs would look much nicer this way.&lt;/p&gt;
&lt;p&gt;The beauty of this is that &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; transforms to &lt;code&gt;comp&lt;/code&gt; almost one-to-one.
The problem is, that it is counter-intuitive because for ordinary functions the order is the opposite.
So keep that in mind.&lt;/p&gt;
&lt;p&gt;For ordinary function, the composition works like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; same as the expression below&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (expressions are aligned for clarity)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For transducers, it works exactly the same, except the argument we&amp;rsquo;re composing with is not the value, it&amp;rsquo;s a reducing function.
The resulting function processes the value in the order specified by the code, so that&amp;rsquo;s one of the reasons people tend to dislike transducers.
My advice is just to remember that the order for transducer composition is the same as in &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;other-contexts&#34;&gt;Other contexts&lt;/h3&gt;
&lt;p&gt;Now, the reason why transducers are a thing is that when working on other libraries for the Clojure ecosystem, the authors noticed that while mapping, filtering, and reducing a core concept, it can&amp;rsquo;t be reused.
One such example is the &lt;code&gt;clojure.core.async&lt;/code&gt; library.
At one point they needed to map a function over a channel, but you can&amp;rsquo;t really do that.
Items appear on channels only when someone puts them, so &lt;code&gt;map&lt;/code&gt; can&amp;rsquo;t pull on the channel.
Moreover, &lt;code&gt;map&lt;/code&gt; would need an extra channel because it can&amp;rsquo;t put the item back into the original channel.&lt;/p&gt;
&lt;p&gt;Originally, &lt;code&gt;core.async&lt;/code&gt; had its own version of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;, called &lt;code&gt;map&amp;gt;&lt;/code&gt; and &lt;code&gt;filter&amp;gt;&lt;/code&gt;.
However, these were deprecated in favor of transducers.&lt;/p&gt;
&lt;p&gt;Say, &lt;code&gt;get-users&lt;/code&gt; doesn&amp;rsquo;t return you a lazy sequence, but instead returns you a &lt;code&gt;core.async&lt;/code&gt; channel.
How would we need to change our processing pipeline from the lazy variant?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async/chan&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async/pipe&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Imagine we&amp;rsquo;ve changed &lt;code&gt;notify&lt;/code&gt; to accept a channel.
Now, we can create a channel with our transformation pipeline as a transducer.
As a matter of fact, &lt;code&gt;core.async&lt;/code&gt; provides a way of running such actions in parallel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async/chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async/pipeline&lt;/span&gt; 10 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Extracted the transformation into a separate binding makes the code a bit more concise, and reusable.
And that&amp;rsquo;s exactly what transducers are about - we can abstract the action away from how the data arrives and how it should be stored.
Here&amp;rsquo;s another example, with the &lt;code&gt;manifold&lt;/code&gt; library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold.stream/-&amp;gt;source&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/transform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same transformation pipeline works for &lt;code&gt;manifold.stream&lt;/code&gt; because it also accepts transducers with the &lt;code&gt;transform&lt;/code&gt; function.
We can then modify &lt;code&gt;notify&lt;/code&gt; to accept a stream instead of a channel and even have an interop between both libraries.&lt;/p&gt;
&lt;p&gt;So, there you have it - we can process, eager collections, lazy sequences, asynchronous channels, and manifold streams, using the same data pipeline:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users-seq&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;[] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eager-notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users-seq&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async/chan&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async/pipe&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users-chan&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan-notify&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admins&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users-chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold.stream/-&amp;gt;source&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/transform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-pipeline&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stream-notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;final-thoughts&#34;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;While transducers are great, there are always things to consider.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with the elephant in the room - the code using transducers is often &lt;strong&gt;ugly&lt;/strong&gt;.
Like, let&amp;rsquo;s go a bit back and compare these two examples:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;notify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;active-user?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-capabilities&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;admin?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fetch-notification-settings&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-users&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first one is so slick, yet inefficient.
The second one looks like a tool that can do the job efficiently, but you&amp;rsquo;re going to hurt yourself in the process.&lt;/p&gt;
&lt;p&gt;Well, we can refactor the second one a bit more, moving out the &lt;code&gt;comp&lt;/code&gt; call, using &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; on the result, but honestly, it&amp;rsquo;s not often when I see &lt;code&gt;comp&lt;/code&gt; moved out and defined as binding.
More often it&amp;rsquo;s written in this crud form.
However, this can be fixed for many scenarios with macros.
There&amp;rsquo;s a &lt;a href=&#34;https://github.com/johnmn3/injest&#34; target=&#34;_blank&#34;&gt;library&lt;/a&gt; that provides &lt;code&gt;x&amp;gt;&lt;/code&gt; and &lt;code&gt;x&amp;gt;&amp;gt;&lt;/code&gt; macros that automatically use transducers.
Here&amp;rsquo;s what they have in the readme:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10000000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;mapcat &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-by&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (mapv dec)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial + &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;Elapsed time: 8275.319295 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 5000054999994&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10000000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;mapcat &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-by&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (mapv dec)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial + &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; &amp;#34;Elapsed time: 2913.851103 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 5000054999994&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s two to three times the speed increase by one character change.
If we expand the macro, we&amp;rsquo;ll see that it simply builds a transducer with some internal machinery:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10000000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;injest.impl/xfn&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/mapcat&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8713#&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8713#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8713#&lt;/span&gt;)]))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/partition-by&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8714#&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8714#&lt;/span&gt; 5)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial + &lt;/span&gt;10)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8715#&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8715#&lt;/span&gt;}))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/apply&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result of calling &lt;code&gt;injest.impl/xfn&lt;/code&gt; is a function that builds a transducer and passes it into a &lt;code&gt;sequence&lt;/code&gt; call.
So there&amp;rsquo;s no magic, apart from a clever way of transforming the code into this form.&lt;/p&gt;
&lt;p&gt;But, there&amp;rsquo;s another problem with transducers - not every transformation pipeline can be described as one.
Notice that there&amp;rsquo;s a commented-out call to &lt;code&gt;mapv&lt;/code&gt;.
Unlike &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;mapv&lt;/code&gt; doesn&amp;rsquo;t return a transducer, and is always eager.
If we were to refactor this code into &lt;code&gt;comp&lt;/code&gt; we would get an error.
The &lt;code&gt;x&amp;gt;&amp;gt;&lt;/code&gt; macro handles this by breaking the transducer into two parts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10000000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;injest.impl/xfn&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/mapcat&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8724#&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8724#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8724#&lt;/span&gt;)]))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/partition-by&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8725#&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8725#&lt;/span&gt; 5)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;)]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/mapv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dec&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;injest.impl/xfn&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial + &lt;/span&gt;10)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8726#&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p1__8726#&lt;/span&gt;}))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/map&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:temp-value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;even?&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/apply&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s another clever trick, and it certainly helps.&lt;/p&gt;
&lt;p&gt;Now, I don&amp;rsquo;t use this library in practice.
Instead, I tend to write transducers by hand, because I want them to be understandable.
It&amp;rsquo;s easy enough to explain how &lt;code&gt;comp&lt;/code&gt; works with transducers to colleagues once, than to close my eyes and believe that the library will do everything for me.
Maybe I&amp;rsquo;m old-fashioned.&lt;/p&gt;
&lt;p&gt;However, there&amp;rsquo;s another difference that we need to remember about - transducers have a bit different laziness semantics.
You can create lazy sequences using transducers with the &lt;code&gt;sequence&lt;/code&gt; function, however, you should be mindful that any step in your transducer will still be executed eagerly.&lt;/p&gt;
&lt;p&gt;Finally, not all functions provide a transducer counterpart to them.
There are libraries, again, that provide more transducers, but I&amp;rsquo;d much rather see more transducers in the Clojure core.&lt;/p&gt;
&lt;p&gt;And sometimes, there&amp;rsquo;s no need to do that at all - lazy transformations can be fine, or exactly what you need in a particular context.
So don&amp;rsquo;t just rush out replacing all consecutive calls to &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; with a transducer.
Although, if you want to, here&amp;rsquo;s a clj-kondo hook that issues a warning when you use too many lazy transformations in a row:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hooks.thread-macros&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-kondo.hooks-api&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;api&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consecutive-threshold&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduceable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; add more functions if you need&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consecutive-threading&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:node&lt;/span&gt;]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forms&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;node&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forms&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;counter&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;form&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forms&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;contains? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduceable&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;form&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:children&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;api/sexpr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;counter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consecutive-threshold&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;api/reg-finding!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;meta &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;node&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;prefer transducers to consecutive maps or filters in threading macros&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:expensive-threading&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forms&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;counter&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forms&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 0))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &lt;code&gt;.clj-kondo/hooks/thread_macros.clj&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:linters&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:expensive-threading&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:warning&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hooks&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:analyze-call&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hooks.thread-macros/consecutive-threading&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  &lt;code&gt;.clj-kondo/config.edn&lt;/code&gt;
&lt;/div&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2024-01-31-using-transducers/custom-linter.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;That&amp;rsquo;s all from me, and I hope you&amp;rsquo;ve found this post interesting.
Reach out, if you have any interesting examples where transducers were hard to apply, or where they made the code more robust.
And I hope transducers will get a better rep in the future.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Using transducers&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 31 Jan 2024 21:57:00 +0300</pubDate>
    </item><item>
      <title>Thoughts on Crafting Interpreters - Part 3</title>
      <link>https://andreyor.st/posts/2024-01-25-thoughts-on-crafting-interpreters-part-3/</link>
      <guid>https://andreyor.st/posts/2024-01-25-thoughts-on-crafting-interpreters-part-3/</guid>
      <description>&lt;p&gt;The unexpected part!&lt;/p&gt;
&lt;p&gt;I liked hacking on Lox in Zig a lot, so I decided it would be great to make some changes to the language.
It should be good for a better understanding of the book&amp;rsquo;s material, and probably will be a lot of fun!&lt;/p&gt;
&lt;h2 id=&#34;minor-changes-from-the-book&#34;&gt;Minor changes from the book&lt;/h2&gt;
&lt;p&gt;I looked back on what we&amp;rsquo;ve done in the book and decided to do some tweaking.&lt;/p&gt;
&lt;p&gt;First, I made &lt;code&gt;print&lt;/code&gt; to be a function and not a statement.
Making it a statement was understandable, as there was no way to call anything in the language yet, and in order to see some evaluation results &lt;code&gt;print&lt;/code&gt; statement was introduced.
Changing it to be a function has some benefits.&lt;/p&gt;
&lt;p&gt;First, we can pass more than one argument, and automatically concatenate those with a space.
It&amp;rsquo;s not the same as &lt;code&gt;printf&lt;/code&gt; in C, and with other functions that accept format strings in various languages, but still handy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(1, 2, 3) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// prints: 1 2 3\n
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Secondly, we can pass it as a callback to other functions, which can&amp;rsquo;t be done with statements.
Lox isn&amp;rsquo;t a real-world language, so this isn&amp;rsquo;t something that people will probably want to be able to do, but still, it&amp;rsquo;s an advantage over &lt;code&gt;print&lt;/code&gt; being a statement.&lt;/p&gt;
&lt;p&gt;Speaking of passing functions - why are there no lambdas in the book?
IIRC, the first half had a &amp;ldquo;Challenge&amp;rdquo;, for implementing a support of anonymous functions, and in the second half, there was none.
It&amp;rsquo;s not like it&amp;rsquo;s hard either.
I added two possible ways to define an anonymous function.&lt;/p&gt;
&lt;p&gt;The first one has exactly the same syntax as a named function, except you don&amp;rsquo;t specify the name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun (x, y, z) { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x + y + z; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can assign this expression to a variable, or call it immediately:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; var foo = fun (x, y, z) { return x + y + z; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; return foo(1, 2, 3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; return (fun (x, y, z) { return x + y + z; })(4, 5, 6);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;15
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But it&amp;rsquo;s too verbose, so I added another syntax using a backslash:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; var bar = \x,y,z -&amp;gt; x + y + z;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; return bar(1,2,3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; return (\x,y,z-&amp;gt;x+y+z)(4,5,6);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;15
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit terse, and I&amp;rsquo;m not sure if I like it or not, but it works.&lt;/p&gt;
&lt;p&gt;Speaking of backslashes - the book doesn&amp;rsquo;t deal with string escaping at all.
I understand that dealing with it is kinda tricky - you need to escape quotes, escape the already escaped quotes and escape characters, you need to correctly unescape everything when printing, etc.
So it being omitted from the book is OK, I guess, but I decided to implement this in the parser and in the &lt;code&gt;tostring&lt;/code&gt; function that I added as one of the book&amp;rsquo;s &amp;ldquo;Challenges&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; return &amp;#34;\&amp;#34;foo\&amp;#34;&amp;#34;; // nested strings can be escaped
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;\&amp;#34;foo\&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; print(&amp;#34;\&amp;#34;foo\&amp;#34;&amp;#34;); // printing correctly unescapes everything
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;foo&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will play nice with changes I&amp;rsquo;ll describe a bit later.&lt;/p&gt;
&lt;p&gt;As a part of another &lt;a href=&#34;http://craftinginterpreters.com/a-virtual-machine.html#challenges&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Challenge&amp;rdquo;&lt;/a&gt;, I changed the virtual machine in such a way that it avoids consecutive popping and pushing in most of the instructions where possible.
This was supposed to make the VM slightly faster, however, it did not have any effect on speed, at least how I measured it.&lt;/p&gt;
&lt;p&gt;Finally, I decided to add the &lt;code&gt;type&lt;/code&gt; function, so the user will be able to tell what kind of an object the function received.
This will play nicely with what I will talk about a bit later.&lt;/p&gt;
&lt;h2 id=&#34;objects-gone&#34;&gt;Objects gone&lt;/h2&gt;
&lt;p&gt;As you may remember, in my previous post on the topic of this book I &lt;a href=&#34;https://andreyor.st/posts/2024-01-15-thoughts-on-crafting-interpreters-part-2/#classes-and-instances&#34;&gt;said&lt;/a&gt; that I don&amp;rsquo;t want to implement classes, and instead would prefer more general hash tables.
And, I also mentioned that the lack of arrays is a strange decision, that limits language capabilities quite heavily.
So I decided to implement data structures!&lt;/p&gt;
&lt;h2 id=&#34;arrays&#34;&gt;Arrays&lt;/h2&gt;
&lt;p&gt;The first data structure I added was arrays.
Adding arrays was easy enough so I still think it is weird that the book doesn&amp;rsquo;t mention them at all.&lt;/p&gt;
&lt;p&gt;First, I needed a few new instructions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; OPCode = &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;(Code) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    Array,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SetIndex,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GetIndex,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    InvokeFromArray,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I chose to implement the syntax for indexing arrays as in most languages, i.e. &lt;code&gt;array[index]&lt;/code&gt;.
Similarly to how we did with invoking instances, I added other instructions for calling array indexes directly: &lt;code&gt;array[index](args)&lt;/code&gt;.
It&amp;rsquo;s a minor optimization, but I wanted to do it to better grasp it.
This meant that in the scanner I had to implement two new tokens:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- a/src/zig/lox/scanner.zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++ b/src/zig/lox/scanner.zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TokenType = &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    LEFT_BRACKET,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    RIGHT_BRACKET,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// in the scanner&amp;#39;s switch statement:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (c) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;[&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.makeToken(.LEFT_BRACKET),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;]&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.makeToken(.RIGHT_BRACKET),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the compiler, these tokens receive a prefix and infix parse rules:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; makeRules() []ParseRule {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.LEFT_BRACKET)] = .{ .prefix = Parser.array, .infix = Parser.arrayIndex, .precedence = .CALL };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.RIGHT_BRACKET)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rules themselves are simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Parser = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; arrayIndex(self: *Parser, canAssign: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;) LoxError!&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.RIGHT_BRACKET, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;]&amp;#39; after an index.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (canAssign &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.match(.EQUAL)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.SetIndex));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.match(.LEFT_PAREN)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; argCount = &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.argumentList();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.InvokeFromArray));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitByte(argCount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.GetIndex));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; array(self: *Parser, _: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;) LoxError!&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; elemCount: Code = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!self.check(.RIGHT_BRACKET) &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; !self.check(.EOF)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; do = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (do &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; self.match(.COMMA)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                do = &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                elemCount += 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (elemCount == 255)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    self.error_(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can&amp;#39;t have more than 255 array elements.&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.RIGHT_BRACKET, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;]&amp;#39; after expressions.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; arr = (&lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; Array.new(self.vm, elemCount)).obj.asValue();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitBytes(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Array), &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.makeConstant(arr));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitByte(elemCount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, onto the object itself.&lt;/p&gt;
&lt;p&gt;First, I added the new struct, called &lt;code&gt;Array&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Array = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Self = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@This&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    obj: Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    values: ArrayList(Value),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; new(vm: *VM, capacity: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;) LoxError!*Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; obj = &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; Obj.allocate(vm, Self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; out = obj.as(Self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        out.* = Self{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .obj = obj.*,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .values = ArrayList(Value).initCapacity(vm.allocator, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@max&lt;/span&gt;(4, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(capacity)))) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; LoxError.OutOfMemoryError,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; out;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; destroy(self: *Self, vm: *VM) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.values.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vm.allocator.destroy(self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; markValues(self: *Self, vm: *VM) !&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (self.values.items) |value| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; value.mark(vm);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; equal(self: *Self, other: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.values.items.len != other.values.items.len) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (self.values.items, 0..) |item, i| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!item.equal(other.values.items[i])) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, it&amp;rsquo;s basically a thin wrapper around the &lt;code&gt;ArrayList&lt;/code&gt; from Zig&amp;rsquo;s standard library.&lt;/p&gt;
&lt;p&gt;I also implemented the equality semantics.
If array lengths are equal and all elements of both arrays are equal then the arrays are equal.
We don&amp;rsquo;t do the deep comparison if arrays are the same objects.
Pretty standard stuff.&lt;/p&gt;
&lt;p&gt;In the VM, creating the array is straightforward:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; op: OPCode = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@enumFromInt&lt;/span&gt;(frame.readByte());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (op) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    .Array =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; arr = frame.readConstant().as(*Array);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; valueCount = frame.readByte();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (0..valueCount) |i| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            arr.values.append((self.stackTop - (valueCount - i))[0]) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t append to array&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.stackTop -= valueCount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.push(arr.obj.asValue());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Maybe a bit sub-optimal, but we had to do it now, as expressions are not always constant.&lt;/p&gt;
&lt;h2 id=&#34;tables&#34;&gt;Tables&lt;/h2&gt;
&lt;p&gt;A.K.A. dictionaries, hash maps, key-value storage, etc.&lt;/p&gt;
&lt;p&gt;I have a firm belief, that an object is just a special case of a hash map, and not vice-versa.
With closures, anonymous functions, and hash maps we can implement objects and most of their properties without resorting to making it a part of the language.
Well, if we want this to be really efficient, it is probably better to make it part of the language, but I don&amp;rsquo;t care about OOP code efficiency, or OOP at all for that matter.
So I removed all of the code that was related to instances, classes, and objects, and replaced it with a third of the code needed to implement hash tables.&lt;/p&gt;
&lt;p&gt;Same as arrays, hash tables required new syntax.
I decided to do it his way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;=&amp;gt;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;wax&amp;#34;&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Additionally, string keys can be written as &lt;code&gt;.key&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.baz&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;=&amp;gt;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;wax&amp;#34;&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This matches the key access &lt;code&gt;dict.key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Implementing this syntax required adding another character to the scanner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -253,6 +242,7 @@ pub const Scanner = struct {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+            &amp;#39;#&amp;#39; =&amp;gt; return self.makeToken(.HASH),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a new parse rule in the compiler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; makeRules() []ParseRule {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.HASH)] = .{ .prefix = Parser.hashTable, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The rule is again quite simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; hashTable(self: *Parser, _: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;) LoxError!&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.LEFT_BRACE, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;{&amp;#39; before table body.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; kvCount: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (!self.check(.RIGHT_BRACE) &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; !self.check(.EOF)) : (kvCount += 2) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.match(.DOT)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                self.consume(.IDENTIFIER, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect property name after &amp;#39;.&amp;#39;.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; s = &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; String.copy(self.vm, self.previous.name);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitConstant(s.obj.asValue());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.consume(.FAT_ARROW, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;=&amp;gt;&amp;#39; after key expression.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!self.check(.RIGHT_BRACE) &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; !self.check(.EOF))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                self.consume(.COMMA, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;,&amp;#39; after value expression.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.RIGHT_BRACE, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;}&amp;#39; after table body.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (kvCount % 2 != 0) self.error_(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Missing value expression&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (kvCount &amp;gt; 255) self.error_(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;too many key-value expressions&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; table = (&lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; HashTable.new(self.vm)).obj.asValue();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitBytes(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Table), &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.makeConstant(table));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(kvCount));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the VM it&amp;rsquo;s again, pretty straightforward:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; op: OPCode = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@enumFromInt&lt;/span&gt;(frame.readByte());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (op) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    .Table =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; table = frame.readConstant().as(*HashTable);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; valueCount = frame.readByte();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; i = valueCount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (i &amp;gt; 0) : (i -= 2) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; slot = (self.stackTop - i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _ = table.fields.set(slot[0], slot[1]) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t append to array&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.stackTop -= valueCount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.push(table.obj.asValue());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Array indexing also replaced the &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; functions for tables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; tbl = &lt;span style=&#34;&#34;&gt;#&lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; key = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// before:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;get(tbl, key); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// &amp;#34;baz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;set(tbl, key, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// now:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;tbl[key]; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// &amp;#34;baz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;tbl[key] = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Perhaps a bit unconventional to be able to use array indexing on tables, but I find this OK.&lt;/p&gt;
&lt;p&gt;In addition to hash tables, I added hash sets:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; set = &lt;span style=&#34;&#34;&gt;#&lt;/span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I thought about using &lt;code&gt;#{}&lt;/code&gt; syntax as in Clojure, but it meant that I needed to choose what data structure to use once I met any of the keys and decide what was a syntactic error and what wasn&amp;rsquo;t.
For example, is it an incorrect hash set or an incorrect hash map?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;#&lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Perhaps, it was meant to be a hash set, but was confused and added &lt;code&gt;=&amp;gt;&lt;/code&gt; between the elements, because it has the same syntax.
Then the error something like &lt;code&gt;&amp;quot;unexpected token &#39;=&amp;gt;&#39; in the hash set literal&amp;quot;&lt;/code&gt; would be the correct one.
Or, if the programmer wanted a hash map and just forgot to add a value for the first key, then the error would be confusing.
So I chose &lt;code&gt;#[]&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2 id=&#34;multiple-value-returns&#34;&gt;Multiple value returns&lt;/h2&gt;
&lt;p&gt;That was a feature I wanted to add, but couldn&amp;rsquo;t find a suitable way of doing it.&lt;/p&gt;
&lt;p&gt;One thing I don&amp;rsquo;t like about Lua is how it implemented multiple value returns.
It has a lot of gotchas, and when something in the language has a gotcha it&amp;rsquo;s a bad thing in my opinion.
You can read &lt;a href=&#34;https://benaiah.me/posts/everything-you-didnt-want-to-know-about-lua-multivals/&#34; target=&#34;_blank&#34;&gt;this article&lt;/a&gt; for a lot of interesting examples, so I&amp;rsquo;ll keep it brief here.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s a function that returns several values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 1, 2, 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can call a function that accepts multiple values, and pass it the result of calling this function, for example, &lt;code&gt;print&lt;/code&gt; is one such function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(foo()) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- prints 1	2	3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can prepend more arguments before the call to &lt;code&gt;foo&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(0, foo()) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- prints 0	1	2	3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But we can&amp;rsquo;t do the same after the call to &lt;code&gt;foo&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(foo(), 4) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- prints 1	4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a gotcha, and it often hits people when they use &lt;code&gt;table.insert&lt;/code&gt; in combination with some function that can return multiple values.
For example, &lt;code&gt;string.gsub&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; words = {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;world&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; capitalized_words = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _, word &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(words) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   table.insert(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      capitalized_words,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      string.gsub(word, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^%l&amp;#34;&lt;/span&gt;, string.upper)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we execute this code, we&amp;rsquo;ll get the following error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bad argument #2 to &amp;#39;insert&amp;#39; (number expected, got string)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why?
Because &lt;code&gt;string.gsub&lt;/code&gt; returns the string and then the index where the replacement occurred.
And table insert accepts a table, index, and a new value: &lt;code&gt;table.insert(t, 3, &amp;quot;foo&amp;quot;)&lt;/code&gt;.
You can omit the index, and just supply the value like this &lt;code&gt;table.insert(t, &amp;quot;foo&amp;quot;)&lt;/code&gt; and the value will be inserted as the last in the table.
In other words, it&amp;rsquo;s the same as &lt;code&gt;table.insert(t, #t, &amp;quot;foo&amp;quot;)&lt;/code&gt;.
When we pass &lt;code&gt;string.gsub&lt;/code&gt; as the expression that should produce a value, it actually returns two values, and &lt;code&gt;table.insert&lt;/code&gt; thinks that we use it&amp;rsquo;s three-argument arity and fails.&lt;/p&gt;
&lt;p&gt;There are many more gotchas to multiple values than that, and the most annoying one perhaps is that you can&amp;rsquo;t store them in a variable to create a closure.
You have to create a table with your variadic arguments if you want to use them in some other inner function.
In other words, this code is invalid:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      print(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cannot use &amp;#39;...&amp;#39; outside a vararg function near &amp;#39;...&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead, we need to do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- or use table.pack(...) in lua 5.2 and above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; va = {n=select(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt;, ...) ...}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- unpack was moved to table.unpack in Lua 5.2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      print((table.unpack &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; unpack)(va, 1, va.n))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This has a performance penalty, it is inconvenient, and if you have to mix variadic args from multiple functions you have to copy them to a single table, and then unpack them.&lt;/p&gt;
&lt;p&gt;Sorry for this long tangent, but when I was thinking about how I would implement multiple values in Lox.
I&amp;rsquo;m OK with the syntax of Lua here, e.g. &lt;code&gt;return a, b, c&lt;/code&gt; and &lt;code&gt;local a, b, c = foo()&lt;/code&gt;.
However, this was hard to do properly.&lt;/p&gt;
&lt;p&gt;I had to change how the return statement works.
It&amp;rsquo;s not hard, we can read values until we find the &lt;code&gt;;&lt;/code&gt; token.
We also count the values, and emit the count with the instruction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; returnStatement(self: *Parser) LoxError!&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.match(.SEMICOLON)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitReturn();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; valueCount: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; do = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// do-while when?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (do &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; self.match(.COMMA)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            do = &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (valueCount == 255)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                self.error_(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can&amp;#39;t return more than 255 values.&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            valueCount += 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.SEMICOLON, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;;&amp;#39; after return value.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.emitBytes(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Ret), &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(valueCount));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OK, we can emit the necessary code, but what do we do with it?&lt;/p&gt;
&lt;p&gt;One thing we can do is create a slice from the stack and return it as a single value.
Then, when we use it as a function parameter, or in an expression, we do the appropriate thing.
However, this isn&amp;rsquo;t particularly great, because the stack is mutable, and we manipulate it extensibly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; var x = (\-&amp;gt; return 1, 2, 3)();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; print(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 2 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; return x + 10;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;20
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oops, we&amp;rsquo;ve pushed to the beginning of the stack, and x became &lt;code&gt;10&lt;/code&gt;.
Well, perhaps we can keep the stack slice, and just not decrement it, but we need to decide when to decrement it, i.e. once multiple values are no longer used.
Which is hard to track.&lt;/p&gt;
&lt;p&gt;The reason I wanted to be able to store multiple values in a single variable is because I want them to behave more like tuples, but that are always on the stack, no matter what.
So they remain fast, without additional memory allocations.
And to be able to make a closure over the multiple values, so we don&amp;rsquo;t have to fiddle with them like in Lua.
This, however, had problems all over the place.&lt;/p&gt;
&lt;p&gt;I also needed to implement a syntax for assigning multiple values to multiple variables, but I felt that at this point I was kinda burned out with the project.
I&amp;rsquo;m satisfied with the data structures that I added, and other stuff that is not available in the book.
All in all, I feel that I had a good grasp of what this book tried to cover.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Thoughts on Crafting Interpreters - Part 3&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 25 Jan 2024 23:23:00 +0300</pubDate>
    </item><item>
      <title>Thoughts on Crafting Interpreters - Part 2</title>
      <link>https://andreyor.st/posts/2024-01-15-thoughts-on-crafting-interpreters-part-2/</link>
      <guid>https://andreyor.st/posts/2024-01-15-thoughts-on-crafting-interpreters-part-2/</guid>
      <description>&lt;p&gt;This is a second post about the &lt;a href=&#34;http://craftinginterpreters.com/&#34; target=&#34;_blank&#34;&gt;Crafting Interpreters&lt;/a&gt; book by Robert Nystrom.&lt;/p&gt;
&lt;p&gt;In the first post, I&amp;rsquo;ve described my experience with the first half of the book, and the challenges of using a different language with different idioms and practices.
This post will be no different, although I have a bit more to discuss, and the contents aren&amp;rsquo;t actually ~2-year-old weak impressions and remembrances.
That being said, this is a second iteration both on this post and on the book so a lot of frustration I had with the book the first time I went through is coming from memory.
Well, these memories aren&amp;rsquo;t as old, as I did the project more recently, but still, I&amp;rsquo;ll point out when the complaints come from the old version or the new one.&lt;/p&gt;
&lt;p&gt;Same as before, I decided to choose a different implementation language, rather than using the one suggested by the author.
Please note, that this decision isn&amp;rsquo;t done for the sake of just using a different language - I have pretty practical reasons to do that.
Even more so than in the first half of the book.&lt;/p&gt;
&lt;p&gt;For the bytecode VM, Robert chooses the C programming language.
It is again, a reasonable choice, and I agree, that for a book on a language runtime, there are probably no other valid choices.
For a &lt;strong&gt;book&lt;/strong&gt;, that is.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not writing a book, however, so I felt that C is a rather poor choice for an actual implementation.
Not that I&amp;rsquo;m suggesting that C is a bad language for this kind of task - it has several advantages over most others, but in general, C isn&amp;rsquo;t the best pick today.
C demands &lt;strong&gt;a lot&lt;/strong&gt; of knowledge of how computers work, and it is the least forgiving language when it comes to fixing bugs down the line.
We&amp;rsquo;ve been writing C since the 1970s and haven&amp;rsquo;t perfected it by any means.
Memory errors are everywhere, programs segfault, and a lot of projects dedicated to finding errors in C code are basically required for any modern work done in C because humans are, in fact, humans.&lt;/p&gt;
&lt;p&gt;If someone claims that they &lt;em&gt;know C&lt;/em&gt;, they are either lying or are extremely rare cases of people who actually know what they&amp;rsquo;re doing.
I don&amp;rsquo;t think I have ever publicly said that I &lt;em&gt;know&lt;/em&gt; C, but I did work with C professionally in the bare metal context, and it&amp;rsquo;s a whole different story to working with C in the context of the operating system.
So even there we can&amp;rsquo;t say that we really know C if we only use it in one of the many possible contexts where you can use C.
Well, at least I worked with ASM as well, so when I saw the C code I could roughly see what ASM would correspond to it.&lt;/p&gt;
&lt;p&gt;Yes, C is still good for teaching the concepts behind data structures, used for language implementation, as you do have to implement them for yourself a lot.
The context that C is used in often requires this, because libraries might not be available for your specific use case.
So implementing stuff in C, especially given that this language just steps aside and says: &amp;ldquo;go&amp;rdquo;, not holding your hand, not preventing you from doing crazy shit like many modern languages often do.
&lt;em&gt;Oh, so you want to create an array, fill it with random numbers, cast it to the function, and run your machine code you&amp;rsquo;ve just put in - be my guest, that&amp;rsquo;s what we call meta-programming!&lt;/em&gt;
As ridiculous as it is, I have done that in the past.&lt;/p&gt;
&lt;p&gt;But, I don&amp;rsquo;t want to write in C anymore for many reasons.
So, what language did I pick?&lt;/p&gt;
&lt;p&gt;Well, since you have seen the tags for this post, you already know that it is the Zig programming language.
However, I have considered a number of other languages.
Namely Nim, Hare, Zig, Ada, and even OCaml.&lt;/p&gt;
&lt;p&gt;I have already tried Rust for this kind of project before, so I knew that I didn&amp;rsquo;t want to do it again with the same language.
I realized that I don&amp;rsquo;t like Rust in general.
The idea is nice on paper, but I believe it&amp;rsquo;s overly fixated.
And I have my thoughts on the Rust community, so this language isn&amp;rsquo;t really for me.&lt;/p&gt;
&lt;p&gt;But I wanted a language that can be considered a system language, much like C is.
And while Rust is indeed used for Linux kernel, I, myself, can&amp;rsquo;t consider it a system programming language, much like I can&amp;rsquo;t consider C++ to be one, even though you can write a system in it, for example &lt;a href=&#34;https://www.haiku-os.org&#34; target=&#34;_blank&#34;&gt;Haiku&lt;/a&gt;.
You can write systems in all kinds of languages, but I think that a system programming language has to have some pretty specific features and these are usually related to the ability to understand code, not to write one.
Rust and many others failed this for me.&lt;/p&gt;
&lt;p&gt;So, I quickly decided that I didn&amp;rsquo;t want to use &lt;a href=&#34;https://nim-lang.org/&#34; target=&#34;_blank&#34;&gt;Nim&lt;/a&gt; because of its Python-like syntax which I don&amp;rsquo;t like at all.
It may be a decent language, but the other point I don&amp;rsquo;t like about it in comparison to the other is that it is transpiled to C and then compiled, correct me if I&amp;rsquo;m wrong and things have changed since when it was like that.
I don&amp;rsquo;t think that this approach is bad, but I think that C is a poor target to compile to, and I can&amp;rsquo;t be sure that everything I write clearly translates to C without weird shenanigans that can have weird or unexpected behavior.
Although more languages do that, namely ECL and Gambit Scheme, it&amp;rsquo;s not impossible to do this well.
Sadly I think Scheme is a better language than Nim.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://ocaml.org/&#34; target=&#34;_blank&#34;&gt;OCaml&lt;/a&gt; is often brought up when discussing a language for writing compilers.
There are valid reasons to use it, but I&amp;rsquo;m quite unfamiliar with the ML family of languages, so I decided to not use it.
Also, OCaml is often used for its ability to work with LLVM, which isn&amp;rsquo;t what we&amp;rsquo;re doing in the book.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://harelang.org/&#34; target=&#34;_blank&#34;&gt;Hare&lt;/a&gt; is a relatively new language by Drew DeVault.
From what I&amp;rsquo;ve seen about this language it seems interesting, and it has a nice article &lt;a href=&#34;https://harelang.org/blog/2021-02-09-hare-advances-on-c/&#34; target=&#34;_blank&#34;&gt;listing the advantages over C&lt;/a&gt;.
However, the documentation was almost non-existent at the moment I started this project, and I didn&amp;rsquo;t want to dive into a language that was in so early stages of its development.
I have vague plans on maybe doing a Forth implementation in Hare in the future, so I&amp;rsquo;ll get to try it eventually.
I would say that Hare was a close second to me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.adaic.org/&#34; target=&#34;_blank&#34;&gt;Ada&lt;/a&gt; seems like an interesting language, and I have read the &lt;em&gt;hellscape&lt;/em&gt; of a code from one of the projects done by a member of a community in which I hang out.
While it seems like a capable language, I didn&amp;rsquo;t like it that much to try it myself.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also &lt;a href=&#34;https://odin-lang.org/&#34; target=&#34;_blank&#34;&gt;Odin&lt;/a&gt;&amp;hellip; I have never heard of this language and it&amp;rsquo;s being used anywhere, but according to their web page, it&amp;rsquo;s basically everywhere.
That seems like a stretch for a project that started in 2016.
Zig started in 2015 and had no stable release yet, and Odin claims to be professionally used in so many game studios and other companies, and yet I haven&amp;rsquo;t heard of it at all!
I consider myself a language enthusiast, yet somehow this language completely dodged my field of view.
Maybe they&amp;rsquo;re that good, I don&amp;rsquo;t know, but I decided that I&amp;rsquo;ll pass.&lt;/p&gt;
&lt;p&gt;Jai, a language by Jonathan Blow, also seemed interesting to try out, but I feel that its aim at being a replacement for C++ in the game programming field is not exactly what I&amp;rsquo;m looking for.
At the time of writing, it&amp;rsquo;s still in a closed beta test, so it&amp;rsquo;s hard to get hands on it, and judging from what I have seen in the videos, it&amp;rsquo;s not like I would use this language for this particular project either.&lt;/p&gt;
&lt;p&gt;Before you ask, I haven&amp;rsquo;t considered Go for this project, because I simply don&amp;rsquo;t like Go.
There&amp;rsquo;s the &lt;a href=&#34;https://interpreterbook.com&#34; target=&#34;_blank&#34;&gt;interpreterbook&lt;/a&gt; book which is oddly similarly named to the book discussed in this post, and it is written in Go, so you don&amp;rsquo;t even have to go through translating C to Go if you want to learn how to design a language if Go is your thing.
Well, I have my reasons to dislike Go, but I don&amp;rsquo;t want to go into them here.
Maybe next time.&lt;/p&gt;
&lt;p&gt;And yes, there are many more languages that can be used for this kind of task - obviously, I can&amp;rsquo;t compare all of them.
So I had to stop somewhere.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://ziglang.org/&#34; target=&#34;_blank&#34;&gt;Zig&lt;/a&gt; programming language caught my eye a few years ago after it was pointed out to me as a response to my &lt;a href=&#34;https://andreyor.st/posts/2020-04-06-c-needs-a-better-syntax/&#34;&gt;rant&lt;/a&gt; about C.
It is more mature than Hare, and as far as I know, the 1.0.0 release is not as far away.
And for what it&amp;rsquo;s worth, it is closest to C in many ways that Ada or Rust are not.
So I decided that it would be a proper pick for the second half of the book.&lt;/p&gt;
&lt;h2 id=&#34;zig&#34;&gt;Zig&lt;/h2&gt;
&lt;p&gt;So I chose Zig.
At the moment of writing this post, the latest release is 0.11.0, which is important to note as Zig is still constantly changing.
While this is a good thing, and I understand that Zig had no stable release yet, I am spoiled.
I am spoiled by languages with the stable core, like Clojure, where you can find a 13-year-old code and run it with the modern version of Clojure.
That&amp;rsquo;s not how it works with Zig.
A lot of code I&amp;rsquo;ve tried during this experiment did not work because it was written for an older version of Zig.&lt;/p&gt;
&lt;p&gt;As you may remember from part 1 - this is a second try on writing the second half of the book in Zig.
The first try wasn&amp;rsquo;t successful, and I&amp;rsquo;m going to discuss this separately later in this post.
During the first iteration, I had to learn many things about the language and its build system.
After I hit the point where my implementation did not work (for reasons described later), I decided to delete everything and start over (for reasons described later).&lt;/p&gt;
&lt;p&gt;So I took a considerable amount of time to rest from this project and in the meantime, Zig 0.11.0 was released.
This is important because the previous run was done using Zig 0.10.0, and I deleted everything, &lt;strong&gt;except&lt;/strong&gt; for the &lt;code&gt;build.zig&lt;/code&gt; that I had spent a lot of time creating to fulfill my needs.
And now it doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;That made me realize that I didn&amp;rsquo;t actually spend any time in the previous post talking about the build system.
So let&amp;rsquo;s do that right now!&lt;/p&gt;
&lt;h3 id=&#34;clojure-build-system&#34;&gt;Clojure build system&lt;/h3&gt;
&lt;p&gt;So, in the Clojure version of the Lox language, I opted to use the &lt;code&gt;deps.edn&lt;/code&gt; which is pretty much the standard way to create projects in Clojure.
There are other systems that can help manage projects, notably Leiningen, but I like to do things manually, for better understanding, so when I can I use stuff like deps.
And unlike Leiningen, deps doesn&amp;rsquo;t come with the automatic building of your project - you have to make it by yourself.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s actually great!
I like the idea that builds are programs because you can write custom builds that are specific to your project&amp;rsquo;s needs.
Of course, most projects don&amp;rsquo;t need anything fancy, so there is a library that provides the basic stuff you&amp;rsquo;ll probably need.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the &lt;code&gt;build.clj&lt;/code&gt; looks like for CljLox:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.tools.build.api&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lox&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;version&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.0.%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/git-count-revs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;class-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;target/clojure/classes&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;basis&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/create-basis&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:project&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;deps.edn&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uber-file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;target/clojure/%s-%s-standalone.jar&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;version&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clean&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/delete&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:path&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;target/clojure&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uber&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clean&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/copy-dir&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:src-dirs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:target-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;class-dir&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/compile-clj&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:basis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;basis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:src-dirs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:class-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;class-dir&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/uber&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:class-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;class-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:uber-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;uber-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:basis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;basis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:main&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lox.core&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it!&lt;/p&gt;
&lt;p&gt;I like the idea of using the number of commits since the repository creation as the last component of the version, and the build library provides a function for that: &lt;code&gt;b/git-count-revs&lt;/code&gt;.
We do have to specify some paths, create a basis, whatever it is, and just define the compilation functions.
We then execute it like &lt;code&gt;clojure -T:build uber&lt;/code&gt;, and it creates the &lt;code&gt;lox-0.0.123-standalone.jar&lt;/code&gt; file that we can later run with the &lt;code&gt;java -jar&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Simple and effective.
If my project required additional steps I could just define more functions to do these steps.
Let&amp;rsquo;s compare that to Zig, shall we?&lt;/p&gt;
&lt;h3 id=&#34;zig-build&#34;&gt;Zig build&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s the entire &lt;code&gt;build.zig&lt;/code&gt; for the previous version of ZigLox:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; std = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;std&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Version = std.builtin.Version;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Builder = std.build.Builder;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; print = std.debug.print;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; LibExeObjStep = std.build.LibExeObjStep;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Mode = std.builtin.Mode;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; CrossTarget = std.zig.CrossTarget;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Step = std.build.Step;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; trimRight = std.mem.trimRight;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; parseInt = std.fmt.parseInt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; exit = std.process.exit;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; fs = std.fs;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; MAJOR = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; MINOR = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; gitCountRevs(b: *Builder) &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; code: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt; = &lt;span style=&#34;font-weight:bold&#34;&gt;undefined&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    b: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; commits_num = trimRight(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            b.execAllowFail(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;amp;[_][]&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;{ &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;git&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-C&amp;#34;&lt;/span&gt;, b.build_root, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rev-list&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;HEAD&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--count&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;amp;code,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Ignore,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt; :b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; parseInt(&lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;, commits_num, 10) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt; :b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unable to count number of revs&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exit(1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; getVersion(b: *Builder) Version {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Version{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .major = MAJOR,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .minor = MINOR,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .patch = gitCountRevs(b),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isZigFile(name: []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; std.mem.eql(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, name[name.len - 4 ..], &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.zig&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// Automatically resolves packages under the source directory.  Adds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// packages to the `exe`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; resolveAndAddPackages(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    src_dir: []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    allocator: std.mem.Allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exe: *LibExeObjStep,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; dir = std.fs.cwd().openIterableDir(src_dir, .{}) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; exit(2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; iterator = dir.iterate();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (iterator.next() &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) |path| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (isZigFile(path.name)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; package_name = path.name[0 .. path.name.len - 4];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; src_path = fs.path.join(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;amp;[_][]&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;{ src_dir, path.name },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; exit(3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            exe.addPackagePath(package_name, src_path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// Automatically finds tests under the test directory, adds the test
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// to the build `step`, and adds all necessary packages for test to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// run.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; resolveAndAddTests(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    b: *Builder,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    test_dir: []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    allocator: std.mem.Allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mode: Mode,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    target: CrossTarget,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    step: *Step,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; dir = std.fs.cwd().openIterableDir(test_dir, .{}) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; exit(2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; iterator = dir.iterate();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (iterator.next() &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) |path| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (isZigFile(path.name)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; test_path = fs.path.join(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;amp;[_][]&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;{ test_dir, path.name },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; exit(3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; tests = b.addTest(test_path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            resolveAndAddPackages(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/zig/lox&amp;#34;&lt;/span&gt;, allocator, tests);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            tests.setTarget(target);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            tests.setBuildMode(mode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            step.dependOn(&amp;amp;tests.step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; build(b: *Builder) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; arena.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; allocator = arena.allocator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; version = getVersion(b);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; version_string = b.fmt(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{[major]d}.{[minor]d}.{[patch]d}&amp;#34;&lt;/span&gt;, version);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; target = b.standardTargetOptions(.{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; mode = b.standardReleaseOptions();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; exe = b.addExecutable(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        b.fmt(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lox-{s}&amp;#34;&lt;/span&gt;, .{version_string}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/zig/lox/main.zig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exe.setTarget(target);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exe.setBuildMode(mode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    exe.install();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; run_cmd = exe.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    run_cmd.step.dependOn(b.getInstallStep());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (b.args) |args| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        run_cmd.addArgs(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; run_step = b.step(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;run&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Run the app&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    run_step.dependOn(&amp;amp;run_cmd.step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; test_step = b.step(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Run unit tests&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; test_dir = fs.path.join(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;amp;[_][]&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;{ &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;zig&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lox&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; exit(1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    resolveAndAddTests(b, test_dir, allocator, mode, target, test_step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s not that big, but the amount of boilerplate you have to do, even though the language has a build library is far greater than in Clojure.
I do understand that these things pursue different goals, but does it really need to be that complicated?&lt;/p&gt;
&lt;p&gt;Actually, let me explain why it is so complicated.
You see, I have a quite specific project layout in mind:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Lox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── build.clj
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── build.zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── deps.edn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── clojure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   │   └── lox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   │       └── sources.clj
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│       └── lox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│           └── sources.zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── clojure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── clojure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   └── lox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       └── test_sources.clj
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   └── various_test_files
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── zig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── lox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            └── test_sources.zig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the sources are located in the &lt;code&gt;src&lt;/code&gt; directory, and the tests are located in the &lt;code&gt;test&lt;/code&gt; directory.
And each implementation has a language directory in there, so Clojure sources are in the &lt;code&gt;src/clojure&lt;/code&gt; and the Zig sources are in &lt;code&gt;src/zig&lt;/code&gt;.
The same goes for tests.&lt;/p&gt;
&lt;p&gt;Unfortunately, I couldn&amp;rsquo;t find a way to have tests outside of the source directory, so I had to dance around, creating my own solution for this self-introduced problem.
Is it that uncommon to put tests into a separate directory, outside of the source directory?
Let&amp;rsquo;s look at other languages.&lt;/p&gt;
&lt;p&gt;In Java, this is the norm, same in Clojure.
I like this actually, tests are separate entities, they don&amp;rsquo;t have anything to do with the source code.
I mean, the source is for the actual application or the library you ship to the consumer.
The tests are for you, the developer, not for the consumer.&lt;/p&gt;
&lt;p&gt;In Rust, the tests usually are in the same file as the source code.
When I was writing in Rust I kinda liked it, but only, seriously, &lt;strong&gt;only&lt;/strong&gt; because before Rust I was writing C professionally, and tests in C are, well, they&amp;rsquo;re not standardized, to say the least.
So having Rust giving you tools to write and run tests was a huge step up from C, but that was the only step up.&lt;/p&gt;
&lt;p&gt;In Go it is possible to put tests in a different directory, and I&amp;rsquo;ve seen projects doing it, so I guess that&amp;rsquo;s a fine part of Go.&lt;/p&gt;
&lt;p&gt;What else can we look at? Nim? Seems that putting tests into a separate directory is possible there.
Hare? From what I can see, the projects have either &lt;code&gt;+test.ha&lt;/code&gt; or just &lt;code&gt;test.ha&lt;/code&gt; files in the same place where the sources are - not sure if this is the only way it can work, the hare docs are sparse on the details here.&lt;/p&gt;
&lt;p&gt;Well, I guess there&amp;rsquo;s no single answer to this question, but I don&amp;rsquo;t see why a language would forbid putting tests whenever the project author sees fit.
And in Zig, well, while it was hard to make it, and make it fully automatic, remember - the build is a program.
You can do whatever you want, as long as the tooling gives you the ability, and in the case of Zig, the build system can do that.
Well, at least it could in 0.10.0, but now I have to rewrite it for 0.11.0.&lt;/p&gt;
&lt;p&gt;I had a few hiccups and managed to do that, so I&amp;rsquo;m not going to complain that much here, but I still think it&amp;rsquo;s too complicated.
I mean, it&amp;rsquo;s not as complicated as it was in 0.10.0, so that&amp;rsquo;s good, but it is still a lot of manual work.
Here&amp;rsquo;s a diff with the previous version so you can feel the amount of subtle changes I had to make to make this thing compile again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -1,11 +1,10 @@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const std = @import(&#34;std&#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-const Version = std.builtin.Version;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-const Builder = std.build.Builder;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+const Builder = std.Build;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+const Step = Builder.Step;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const print = std.debug.print;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-const LibExeObjStep = std.build.LibExeObjStep;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+const CompStep = Step.Compile;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const Mode = std.builtin.Mode;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const CrossTarget = std.zig.CrossTarget;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-const Step = std.build.Step;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const trimRight = std.mem.trimRight;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const parseInt = std.fmt.parseInt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const exit = std.process.exit;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -14,6 +13,12 @@ const fs = std.fs;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const MAJOR = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const MINOR = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+const Version = struct {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    major: u32,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    minor: u32,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    commits: u32,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fn gitCountRevs(b: *Builder) u32 {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     var code: u8 = undefined;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     b: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -46,10 +51,10 @@ fn isZigFile(name: []const u8) bool {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /// Automatically resolves packages under the source directory.  Adds
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /// packages to the `exe`.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-fn resolveAndAddPackages(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+fn resolveAndAddModules(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    b: *Builder,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     src_dir: []const u8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    allocator: std.mem.Allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    exe: *LibExeObjStep,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    exe: *CompStep,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ) void {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     const dir = std.fs.cwd().openIterableDir(src_dir, .{}) catch exit(2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     var iterator = dir.iterate();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -57,11 +62,8 @@ fn resolveAndAddPackages(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     while (iterator.next() catch null) |path| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         if (isZigFile(path.name)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             const package_name = path.name[0 .. path.name.len - 4];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            const src_path = fs.path.join(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-                allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-                &amp;amp;[_][]const u8{ src_dir, path.name },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            ) catch exit(3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            exe.addPackagePath(package_name, src_path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+            const src_path = b.pathJoin(&amp;amp;.{ src_dir, path.name });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+            exe.addModule(package_name, b.createModule(.{ .source_file = .{ .path = src_path } }));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -71,9 +73,9 @@ fn resolveAndAddPackages(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /// run.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fn resolveAndAddTests(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     b: *Builder,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    src_dir: []const u8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     test_dir: []const u8,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    allocator: std.mem.Allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    mode: Mode,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    optimize: Mode,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     target: CrossTarget,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     step: *Step,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ) void {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -82,52 +84,41 @@ fn resolveAndAddTests(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     while (iterator.next() catch null) |path| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         if (isZigFile(path.name)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            const test_path = fs.path.join(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-                allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-                &amp;amp;[_][]const u8{ test_dir, path.name },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            ) catch exit(3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            const tests = b.addTest(test_path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            resolveAndAddPackages(&#34;src/zig/lox&#34;, allocator, tests);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            tests.setTarget(target);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            tests.setBuildMode(mode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-            step.dependOn(&amp;amp;tests.step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+            const tests = b.addTest(.{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                .name = path.name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                .root_source_file = .{ .path = b.pathJoin(&amp;amp;.{ test_dir, path.name }) },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                .target = target,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                .optimize = optimize,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+            });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+            resolveAndAddModules(b, src_dir, tests);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+            step.dependOn(&amp;amp;b.addRunArtifact(tests).step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; pub fn build(b: *Builder) void {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    defer arena.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const allocator = arena.allocator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const version = getVersion(b);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const version_string = b.fmt(&#34;{[major]d}.{[minor]d}.{[patch]d}&#34;, version);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const version = b.fmt(&#34;{[major]d}.{[minor]d}.{[commits]d}&#34;, getVersion(b));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     const target = b.standardTargetOptions(.{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const mode = b.standardReleaseOptions();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const exe = b.addExecutable(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        b.fmt(&#34;lox-{s}&#34;, .{version_string}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        &#34;src/zig/lox/main.zig&#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    exe.setTarget(target);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    exe.setBuildMode(mode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    exe.install();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const run_cmd = exe.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    run_cmd.step.dependOn(b.getInstallStep());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    if (b.args) |args| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        run_cmd.addArgs(args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const optimize = b.standardOptimizeOption(.{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const src_dir = b.pathJoin(&amp;amp;.{ &#34;src&#34;, &#34;zig&#34;, &#34;lox&#34; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const main = b.pathJoin(&amp;amp;.{ src_dir, &#34;main.zig&#34; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const exe = b.addExecutable(.{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+        .name = b.fmt(&#34;lox-{s}&#34;, .{version}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+        .root_source_file = .{ .path = main },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+        .target = target,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+        .optimize = optimize,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    b.installArtifact(exe);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const run_cmd = b.addRunArtifact(exe);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     const run_step = b.step(&#34;run&#34;, &#34;Run the app&#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     run_step.dependOn(&amp;amp;run_cmd.step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     const test_step = b.step(&#34;test&#34;, &#34;Run unit tests&#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    const test_dir = fs.path.join(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        &amp;amp;[_][]const u8{ &#34;test&#34;, &#34;zig&#34;, &#34;lox&#34; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    ) catch exit(1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    const test_dir = b.pathJoin(&amp;amp;.{ &#34;test&#34;, &#34;zig&#34;, &#34;lox&#34; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-    resolveAndAddTests(b, test_dir, allocator, mode, target, test_step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+    resolveAndAddTests(b, src_dir, test_dir, optimize, target, test_step);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yet, this isn&amp;rsquo;t a final version of the file&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, just the first working one.
Gotta say, I had to spend a few hours figuring out why tests don&amp;rsquo;t actually run, only to notice a line in the changelog:&lt;/p&gt;
&lt;blockquote&gt;
&lt;h2&gt;addTest No Longer Runs It&lt;/h2&gt;
&lt;p&gt;Before, addTest created and ran a test. Now you need to use b.addRunArtifact to run your test executable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s on me, of course, cuz I haven&amp;rsquo;t taken my time to read the whole changelog.
But it&amp;rsquo;s like 24k words without the code, so can you blame me?
I just had a stroke of passion to restart this project, and I didn&amp;rsquo;t really want to kill it by reading a huge changelog of the language I already don&amp;rsquo;t remember almost completely.
So for me, it is not even a &lt;em&gt;change&lt;/em&gt; log, it&amp;rsquo;s just a log.&lt;/p&gt;
&lt;p&gt;But it now works and that&amp;rsquo;s the only thing that matters.
Hopefully, I&amp;rsquo;ll finish this project before 0.12.0 comes out, and I&amp;rsquo;ll reimplement everything &lt;em&gt;again&lt;/em&gt;.
Oh well, I can just not update, but the language is being improved so I&amp;rsquo;d rather not miss on these improvements.&lt;/p&gt;
&lt;p&gt;With that covered, I think we can actually start with the book!&lt;/p&gt;
&lt;h2 id=&#34;chunks-of-bytecode&#34;&gt;Chunks of Bytecode&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s going to be an ongoing theme with this book: I&amp;rsquo;m not going to re-implement low-level machinery for the sake of implementing it.
It&amp;rsquo;s something I need to say early on, as the book is full of this, and while I understand the author&amp;rsquo;s intent, I&amp;rsquo;m not the type of reader the book really aims for.&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;m talking about is implementing such things as dynamic arrays.
Zig already comes with the dynamic array, called the &lt;code&gt;ArrayList&lt;/code&gt;.
If you&amp;rsquo;re curious enough, you can check how it is implemented, and it is almost exactly the same as what is described in the book.
I implemented it during the first run, looked at it, looked at the standard library implementation, said to myself &amp;ldquo;I got it&amp;rdquo;, and decided not to reinvent the wheel.
These tricks, while neat, are only meaningful to C - in Zig, we can and should use the standard library.&lt;/p&gt;
&lt;p&gt;Even if we don&amp;rsquo;t re-implement all this stuff, there are a lot of differences in implementing things with Zig.
Let&amp;rsquo;s have a look at the code for the chunk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; std = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;std&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; ArrayList = std.ArrayList;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; common = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;common.zig&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Code = common.Code;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; OPCode = common.OPCode;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Allocator = common.Allocator;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; exit = common.exit;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; print = common.print;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; str = common.str;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Chunk = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Self = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@This&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    code: ArrayList(Code),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; init(allocator: Allocator) Chunk {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Chunk{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .code = ArrayList(Code).init(allocator),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; deinit(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.code.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; write(self: *Self, byte: OPCode) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.code.append(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(byte)) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            exit(1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for the instruction&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; simpleInstruction(name: str, offset: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        std.debug.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{s: &amp;lt;16}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, .{name});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; offset + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; disassembleInstruction(self: *Self, offset: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{d:0&amp;gt;4} &amp;#34;&lt;/span&gt;, .{offset});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; opcode = self.code.items[offset];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(OPCode, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@enumFromInt&lt;/span&gt;(opcode))) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Ret =&amp;gt; |op| simpleInstruction(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@tagName&lt;/span&gt;(op), offset),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; |op| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unknown opcode {d}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, .{op});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; offset + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; disassemble(self: *Self, name: str) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;==== {s} ====&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, .{name});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; offset: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (offset &amp;lt; self.code.items.len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            offset = self.disassembleInstruction(offset);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  src/zig/lox/chunk.zig
&lt;/div&gt;
&lt;p&gt;Do you see that barrage of &lt;code&gt;const&lt;/code&gt; definitions at the top?
There will be lots of these things during this post.
As you can actually notice, a dozen came from the &lt;code&gt;common.zig&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; std = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;std&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Allocator = std.mem.Allocator;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; str = []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Code = &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; print = std.debug.print;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; OPCode = &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;(Code) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Ret,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; exit(code: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, msg: str) &lt;span style=&#34;font-weight:bold&#34;&gt;noreturn&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{s}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, .{msg});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    std.process.exit(code);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  src/zig/lox/common.zig
&lt;/div&gt;
&lt;p&gt;Zig claims that the top-level constants don&amp;rsquo;t have to be ordered, which while convenient, I don&amp;rsquo;t think is practically good.
I do prefer a top-down approach, where the most specific things appear at the top, and more general stuff is at the bottom.
So if this isn&amp;rsquo;t your cup of tea, well, sorry, I guess?&lt;/p&gt;
&lt;p&gt;Anyhow, here&amp;rsquo;s the &lt;code&gt;main.zig&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; std = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;std&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Chunk = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;chunk.zig&amp;#34;&lt;/span&gt;).Chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; common = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;common.zig&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; OPCode = common.OPCode;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; main() !&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; arena.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; allocator = arena.allocator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; chunk = Chunk.init(allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; chunk.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk.write(OPCode.Ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk.disassemble(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test chunk&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  src/zig/lox/main.zig
&lt;/div&gt;
&lt;p&gt;If we run it with &lt;code&gt;zig build run&lt;/code&gt;, we get a lovely:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ zig build run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==== test chunk ====
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0000 Ret
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So far so good.
Note, this is code up to the part where we are supposed to add a value array for constants, so it&amp;rsquo;s not like it&amp;rsquo;s the whole code for the chapter.
For now, I won&amp;rsquo;t go into code explanations, it&amp;rsquo;s not that hard right now, you can get the idea just by reading it, and by referring to the book.
But there is a reason why I decided to show it right now.&lt;/p&gt;
&lt;h3 id=&#34;adding-constants&#34;&gt;Adding constants&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s have a look at how the book suggests to add the constants.&lt;/p&gt;
&lt;p&gt;First, we introduce the &lt;code&gt;addConstant&lt;/code&gt; function, which adds a &lt;code&gt;Value&lt;/code&gt; type to the dynamic array of constants.
Next, we use &lt;code&gt;writeChunk&lt;/code&gt;, or in my case &lt;code&gt;chunk.write&lt;/code&gt; to write the constant index in the array to the &lt;code&gt;code&lt;/code&gt; array of the chunk.
Do you see the issue here?
Let&amp;rsquo;s look at the code then.&lt;/p&gt;
&lt;p&gt;The first thing we do is add a new function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; addConstant(self: *Self, value: Value) Code {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.constants.append(value) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        exit(1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for the constant&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@truncate&lt;/span&gt;(self.constants.items.len - 1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may wonder, why am I using &lt;code&gt;@truncate&lt;/code&gt; on the return value, and the return type is &lt;code&gt;Code&lt;/code&gt;?
Especially since the code in the book tells us that it should return an &lt;code&gt;int&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;addConstant&lt;/span&gt;(Chunk* chunk, Value value) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  writeValueArray(&amp;amp;chunk-&amp;gt;constants, value);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; chunk-&amp;gt;constants.count - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, remember, our &lt;code&gt;write&lt;/code&gt; function (&lt;code&gt;writeChunk&lt;/code&gt; in the book) accepts the chunk and an opcode to write.
Initially, I&amp;rsquo;ve made it so that the signature expects the &lt;code&gt;OPCode&lt;/code&gt; enum itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; write(self: *Self, byte: OPCode) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.code.append(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(byte)) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            exit(1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for the instruction&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, that would mean, that if we were to pass the result of &lt;code&gt;addConstant&lt;/code&gt; to it, we would need to convert it to the enum tag, and then immediately convert it back to the &lt;code&gt;Code&lt;/code&gt; type, that the &lt;code&gt;ArrayList&lt;/code&gt; uses to store code in the chunk.
So, I&amp;rsquo;ve changed it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; write(self: *Self, byte: Code) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.code.append(byte) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            exit(1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for the instruction&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can add constants in the &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; main() !&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; arena.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; allocator = arena.allocator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; chunk = Chunk.init(allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; chunk.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; constant = chunk.addConstant(1.2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk.write(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Constant));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk.write(constant);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk.disassemble(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;test chunk&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Still don&amp;rsquo;t see the issue?
Well, &lt;code&gt;@truncate&lt;/code&gt; kinda spoiled it, so I&amp;rsquo;ll get straight to the point - we can only have 256 constants in the Chunk.
The rest will overflow our &lt;code&gt;Code&lt;/code&gt; type, which is, in fact, just a &lt;code&gt;u8&lt;/code&gt; in disguise.&lt;/p&gt;
&lt;p&gt;The book overlooks this for now, as in C truncation happens automatically, but comes back to it in the &amp;ldquo;Challenges&amp;rdquo; section.
And, as you may remember I&amp;rsquo;ve promised that I have a lot to say about the &amp;ldquo;Challenges&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the &amp;ldquo;Challenge&amp;rdquo;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Because &lt;code&gt;OP_CONSTANT&lt;/code&gt; uses only a single byte for its operand, a chunk may only contain up to 256 different constants.
That’s small enough that people writing real-world code will hit that limit.
We could use two or more bytes to store the operand, but that makes every constant instruction take up more space.
Most chunks won’t need that many unique constants, so that wastes space and sacrifices some locality in the common case to support the rare case.&lt;/p&gt;
&lt;p&gt;To balance those two competing aims, many instruction sets feature multiple instructions that perform the same operation but with operands of different sizes.
Leave our existing one-byte &lt;code&gt;OP_CONSTANT&lt;/code&gt; instruction alone, and define a second &lt;code&gt;OP_CONSTANT_LONG&lt;/code&gt; instruction.
It stores the operand as a 24-bit number, which should be plenty.&lt;/p&gt;
&lt;p&gt;Implement this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;writeConstant&lt;/span&gt;(Chunk* chunk, Value value, &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; line) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Implement me...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It adds &lt;code&gt;value&lt;/code&gt; to &lt;code&gt;chunk&lt;/code&gt;’s constant array and then writes an appropriate instruction to load the constant.
Also add support to the disassembler for &lt;code&gt;OP_CONSTANT_LONG&lt;/code&gt; instructions.&lt;/p&gt;
&lt;p&gt;Defining two instructions seems to be the best of both worlds.
What sacrifices, if any, does it force on us?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So here&amp;rsquo;s the problem - I had implemented this in the first run and regretted it many, many times.
So for this run, I&amp;rsquo;m not going to, sorry Robert.&lt;/p&gt;
&lt;p&gt;I mean, the challenge itself isn&amp;rsquo;t hard, however, the book assumes that you don&amp;rsquo;t do them because it is a &lt;em&gt;challenge&lt;/em&gt;, not homework that you &lt;em&gt;have&lt;/em&gt; to do.
So the latter chapters continue as if no challenges were even there - the code in the book still uses the naive truncated approach.&lt;/p&gt;
&lt;p&gt;I do understand that this book is about teaching how to implement a language and not a step-by-step guide.
But later, these challenges made my code so different from what the book gives you that I had several hours-long sessions of looking through the book, figuring out where the particular piece of code came from, and what the intention there was.
All because I had a bug &lt;em&gt;somewhere&lt;/em&gt; and the reason was usually that differences, introduced by the challenges, piled up and combined introducing a subtle bug that made itself visible only after several chapters.&lt;/p&gt;
&lt;p&gt;So, no challenges this time.
All I care about this time is to finish the book and have a working language written in Zig.&lt;/p&gt;
&lt;h3 id=&#34;line-information&#34;&gt;Line information&lt;/h3&gt;
&lt;p&gt;Sike!
Let&amp;rsquo;s do a challenge!&lt;/p&gt;
&lt;p&gt;The book suggests that we can store lines in a dynamic array, for each index of the chunk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk-&amp;gt;lines[chunk-&amp;gt;count] = line;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this is quite inefficient in terms of memory.
And the book mentions that in the &amp;ldquo;Challenges&amp;rdquo; section.
It suggests using a so-called &lt;a href=&#34;https://en.wikipedia.org/wiki/Run-length_encoding&#34; target=&#34;_blank&#34;&gt;Run-length encoding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After scratching my head for a moment, I came up with this solution:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; writeLine(self: *Self, line: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; len = self.lines.items.len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (len &amp;gt; 1 &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.lines.items[len - 2] == line) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.lines.items[len - 1] = self.lines.items[len - 1] + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.lines.append(line) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                exit(1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for line information&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.lines.append(1) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                exit(1, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for line information&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 4:&lt;/span&gt;
  a method in the &lt;code&gt;Chunk&lt;/code&gt; struct
&lt;/div&gt;
&lt;p&gt;It&amp;rsquo;s a rather simple algorithm - we check if the last line is the same as the new one, and if it is, we increase the count, that is stored right next to it.
Otherwise, we append a new line and set its count to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But now we need to extract line information by uncompressing this data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; getLine(self: *&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Self, offset: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; cnt: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; off: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = offset;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (off &amp;gt; 0) loop: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; n: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = self.lines.items[cnt + 1];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (n &amp;gt; 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (off == 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt; :loop;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                off = off - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                n = n - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            cnt = cnt + 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.lines.items[cnt];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 5:&lt;/span&gt;
  a method in the &lt;code&gt;Chunk&lt;/code&gt; struct
&lt;/div&gt;
&lt;p&gt;Simply put, we&amp;rsquo;re decreasing the counter while the offset is greater than zero while increasing the counter each time we&amp;rsquo;ve exhausted the line counter &lt;code&gt;n&lt;/code&gt;.
Sure, it&amp;rsquo;s not a very fast algorithm, and we can probably do it without using loops if I think hard enough, but I&amp;rsquo;m OK with this solution.
It isn&amp;rsquo;t used until the chunk gets disassembled, and this only happens when we debug.&lt;/p&gt;
&lt;p&gt;This challenge I like.
It doesn&amp;rsquo;t affect the overall code of the VM and is more of a lesson in optimization.
We saved some memory, at the expense of a bit slower disassembler, which is fine by me.&lt;/p&gt;
&lt;p&gt;However, seriously, this is probably the last challenge I&amp;rsquo;ll tackle for a long time, so don&amp;rsquo;t get excited.&lt;/p&gt;
&lt;h3 id=&#34;tests&#34;&gt;Tests&lt;/h3&gt;
&lt;p&gt;As a final thing in this chapter, the book suggests testing your code.
And here&amp;rsquo;s the thing - it&amp;rsquo;s a great suggestion, only this book will make you hate your decision to test the code.
I&amp;rsquo;m a bit exaggerating here, but keep in mind, during this chapter we&amp;rsquo;ve already changed some parts of the &lt;code&gt;Chunk&lt;/code&gt; code several times.&lt;/p&gt;
&lt;p&gt;First, we introduced the &lt;code&gt;write&lt;/code&gt; method, and it accepted the &lt;code&gt;OPCode&lt;/code&gt; enum.
Next, we introduced the &lt;code&gt;addConstant&lt;/code&gt; method, and it required us to change the &lt;code&gt;write&lt;/code&gt; to accept the &lt;code&gt;Code&lt;/code&gt; instead.
Finally, we&amp;rsquo;ve added support for line information, changing the &lt;code&gt;write&lt;/code&gt; method once again.&lt;/p&gt;
&lt;p&gt;You may think that that&amp;rsquo;s fine, as we did it during one chapter, and the tests should be written after we complete it.
Well, &lt;abbr title=&#34;Tests Delay Deployment&#34;&gt;TDD&lt;/abbr&gt; people may disagree with you.
I&amp;rsquo;m not a TDD person, I usually test things as I go in the REPL, and then, once I&amp;rsquo;m satisfied I write proper tests to prevent later breakage.
But Zig doesn&amp;rsquo;t have a REPL, so testing it this way won&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;So, while Robert claims that: &amp;ldquo;I wrote a test suite for Lox before I wrote a single word of this book.&amp;rdquo;, I&amp;rsquo;d be cautious when writing tests for this book&amp;rsquo;s code.
Probably his claim is true, especially if he knew what the result would be and wrote a test for it.
Or, maybe the book was simply written after the implementation of the language became a thing, which then doesn&amp;rsquo;t matter if the tests were written upfront or not.&lt;/p&gt;
&lt;p&gt;I tend to write tests either during the chapter or at the end of it.
And at the first run, I did exactly that.
But, as we&amp;rsquo;ll see later, you&amp;rsquo;ll have to discard or rework &lt;strong&gt;a lot&lt;/strong&gt; of tests due to changes in the code.
And often the changes are dramatic, so I&amp;rsquo;m not sure if it makes sense to write too many tests early on.&lt;/p&gt;
&lt;h2 id=&#34;a-virtual-machine&#34;&gt;A Virtual Machine&lt;/h2&gt;
&lt;p&gt;This chapter is mostly straightforward, except for a few shenanigans we have to make because Zig is different.
The first thing I would like to talk about is pointers in various programming languages.&lt;/p&gt;
&lt;p&gt;In C we &lt;em&gt;basically&lt;/em&gt; have one kind of pointer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SomeType * variable;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This really can be anything.
It can be a pointer to a single location, or it can be a pointer to an array, or even to a place somewhere in a set array.
Well, there&amp;rsquo;s also a function pointer in C, but we&amp;rsquo;re not going to look at it now.&lt;/p&gt;
&lt;p&gt;Zig, on the other hand, has quite a few types of pointers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*T&lt;/code&gt; - single-item pointer to exactly one item.
&lt;ul&gt;
&lt;li&gt;Supports deref syntax: &lt;code&gt;ptr.*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[*]T&lt;/code&gt; - many-item pointer to an unknown number of items.
&lt;ul&gt;
&lt;li&gt;Supports index syntax: &lt;code&gt;ptr[i]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supports slice syntax: &lt;code&gt;ptr[start..end]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supports pointer arithmetic: &lt;code&gt;ptr + x&lt;/code&gt;, &lt;code&gt;ptr - x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T&lt;/code&gt; must have a known size&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*[N]T&lt;/code&gt; - pointer to N items, same as a single-item pointer to an array.
&lt;ul&gt;
&lt;li&gt;Supports index syntax: &lt;code&gt;array_ptr[i]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supports slice syntax: &lt;code&gt;array_ptr[start..end]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supports len property: &lt;code&gt;array_ptr.len&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[]T&lt;/code&gt; - is a slice (a fat pointer, which contains a pointer of type &lt;code&gt;[*]T&lt;/code&gt; and a length).
&lt;ul&gt;
&lt;li&gt;Supports index syntax: &lt;code&gt;slice[i]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supports slice syntax: &lt;code&gt;slice[start..end]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supports len property: &lt;code&gt;slice.len&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, we can&amp;rsquo;t just write &lt;code&gt;variable: *SomeType&lt;/code&gt; in Zig and use it like we can in C.
I believe this is a good thing, and in practice, it does eliminate bugs related to accessing ordinary pointers as arrays.
On the other hand, it is quite tedious to write code with such a system.&lt;/p&gt;
&lt;p&gt;To get what I mean, let&amp;rsquo;s have a look at how the instruction pointer concept is implemented by the book:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Chunk* chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;uint8_t&lt;/span&gt;* ip;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} VM;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;InterpretResult &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interpret&lt;/span&gt;(Chunk* chunk) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  vm.chunk = chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  vm.ip = vm.chunk-&amp;gt;code;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;re looking at the &lt;code&gt;VM&lt;/code&gt; struct that holds the currently executed &lt;code&gt;chunk&lt;/code&gt; and an instruction pointer &lt;code&gt;ip&lt;/code&gt;.
In the &lt;code&gt;interpret&lt;/code&gt; function we set the VM&amp;rsquo;s current chunk, and its instruction pointer to point to the &lt;code&gt;code&lt;/code&gt; from the chunk.
As you may remember the &lt;code&gt;Chunk&lt;/code&gt; struct contains the &lt;code&gt;code&lt;/code&gt; field which is a dynamic array: &lt;code&gt;uint8_t * code&lt;/code&gt;.
So by saying &lt;code&gt;vm.ip = vm.chunk-&amp;gt;code&lt;/code&gt; we essentially say that &lt;code&gt;ip&lt;/code&gt; now holds the same address that was in the &lt;code&gt;code&lt;/code&gt; field.
Hopefully, it&amp;rsquo;s the start of the array!&lt;/p&gt;
&lt;p&gt;With that, we can now inspect the &lt;code&gt;run&lt;/code&gt; function.
For now, all we really care about is how it uses the instruction pointer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;static&lt;/span&gt; InterpretResult &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;run&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define READ_BYTE() (*vm.ip++)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (instruction = READ_BYTE()) {&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/* ... */&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#undef READ_BYTE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aha, C tricks!
The &lt;code&gt;READ_BYTE&lt;/code&gt; is a substitution macro that simply increments the pointer with &lt;code&gt;++&lt;/code&gt;, dereferencing the resulting one with &lt;code&gt;*&lt;/code&gt;.
It&amp;rsquo;s a clever trick - too clever, even, because of the operator precedence rules in C.
The &lt;code&gt;++&lt;/code&gt; has to happen &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;*&lt;/code&gt; because otherwise, we would increment the dereferenced value.
But the effect of &lt;code&gt;++&lt;/code&gt; has to happen &lt;strong&gt;after&lt;/strong&gt; we dereference the pointer, otherwise, we would dereference the &lt;em&gt;next&lt;/em&gt; address.
This code can be rewritten into two separate expressions, like &lt;code&gt;uint8_t val = *ip; ip = ip + 1;&lt;/code&gt; but it&amp;rsquo;s hard to use that in a macro, that itself is used in the expression context.
So the &lt;code&gt;*ptr++&lt;/code&gt; form is a quite common trick.&lt;/p&gt;
&lt;p&gt;But here&amp;rsquo;s the thing - the &lt;code&gt;ip&lt;/code&gt; is not an array, it just happens to hold an address to an array.
Uh oh.&lt;/p&gt;
&lt;p&gt;Well, that&amp;rsquo;s a common thing in C, so let&amp;rsquo;s look at Zig.
Now, I&amp;rsquo;m not really experienced in Zig&amp;rsquo;s pointers but after poking around I think we have several options:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; VM = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk: *Chunk, &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// store a pointer to the chunk
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    ip: []Code, &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// and a fat pointer to the array
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// methods ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 6:&lt;/span&gt;
  Option №1
&lt;/div&gt;
&lt;p&gt;Here I have the &lt;code&gt;[*]T&lt;/code&gt; type of pointer because we&amp;rsquo;re going to point to an array because the &lt;code&gt;Chunk&lt;/code&gt; stores items in a dynamic array.
We can implement the &lt;code&gt;interpret&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt; functions as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; interpret(self: *VM, chunk: *Chunk) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.chunk = chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.ip = chunk.code.items;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; run(self: *VM) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; instr = self.ip[0]; self.ip += 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (instr) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can put the pointer reading into an &lt;code&gt;inline&lt;/code&gt; function, but that&amp;rsquo;s beside the point.
Look at how we have to dereference this kind of pointer: &lt;code&gt;ip[0]&lt;/code&gt;.
Unlike in C, we can&amp;rsquo;t use a single-item pointer dereference syntax here, because it&amp;rsquo;s not a single-item pointer!&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try a single-item pointer then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; VM = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk: *Chunk, &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// store a pointer to the chunk
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    ip: *Code, &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// and a pointer to a place in the array
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// methods ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 7:&lt;/span&gt;
  Option №2
&lt;/div&gt;
&lt;p&gt;Now we have a single-item pointer for the instruction pointer (makes sense), but let&amp;rsquo;s look at how we have to use it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; interpret(self: *VM, chunk: *Chunk) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.chunk = chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.ip = &amp;amp;chunk.code.items[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; run(self: *VM) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; instr = self.ip.*;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.ip = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrCast&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;([*]Code, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrCast&lt;/span&gt;(self.ip)) + 1);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (instr) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ugh, that&amp;rsquo;s looking nasty.
We have to do two pointer casts to do a simple thing like that.
Looking at it now the &lt;code&gt;ip[0]&lt;/code&gt; doesn&amp;rsquo;t look that out of place.&lt;/p&gt;
&lt;p&gt;But then the book does this kind of thing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;disassembleInstruction(vm.chunk, (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt;)(vm.ip - vm.chunk-&amp;gt;code));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you recall the &lt;code&gt;disassembleInstruction&lt;/code&gt; signature, the second argument is an integer offset.
So we do all this pointer arithmetic here and there just to convert it back to an index in the array.
And that&amp;rsquo;s our option three:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; VM = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chunk: *Chunk, &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// store a pointer to the chunk
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    ip: []Code,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ic: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;, &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// and an index!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// methods ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 8:&lt;/span&gt;
  Option №3
&lt;/div&gt;
&lt;p&gt;This does require a bit different approach in the rest of the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; interpret(self: *VM, chunk: *Chunk) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.chunk = chunk;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.ip = chunk.code.items;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    self.ic = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; run(self: *VM) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; instr = self.ip[self.ic]; self.ic += 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (instr) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can simply use the &lt;code&gt;vm.disassembleInstruction(self.ip)&lt;/code&gt; to disassemble the instruction avoiding all of the pointer arithmetic altogether.
Now, I&amp;rsquo;m sure the raw pointer for this kind of task is more appealing, and probably it is slightly faster.
But to me, this looks like a premature optimization, at least for now.
So that&amp;rsquo;s the way I decided to do it for my implementation.&lt;/p&gt;
&lt;p&gt;Another thing I want to touch here is the return type of the &lt;code&gt;interpret&lt;/code&gt; function.
In the book, the return type is called &lt;code&gt;InterpretResult&lt;/code&gt; and it is a enumeration with simple tags: &lt;code&gt;INTERPRET_OK&lt;/code&gt;, &lt;code&gt;INTERPRET_COMPILE_ERROR&lt;/code&gt;, &lt;code&gt;INTERPRET_RUNTIME_ERROR&lt;/code&gt;.
When we reach the &lt;code&gt;OP_RETURN&lt;/code&gt; the result of the &lt;code&gt;run&lt;/code&gt; function is the &lt;code&gt;INTERPRET_OK&lt;/code&gt; tag.
At the end of the chapter, after we&amp;rsquo;ve implemented the stack and basic arithmetic operations we read the last value on the stack and print it before we exit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; OP_RETURN: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        printValue(pop());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; INTERPRET_OK;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While this is in the spirit of C, we can do better.
And in fact, we have to do better, as we need to write tests, as the book suggested.
It&amp;rsquo;s hard to write tests if you don&amp;rsquo;t have access to the result of interpretation, so my &lt;code&gt;Result&lt;/code&gt; type is defined as &lt;code&gt;union(enum)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Result = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    OK: Value,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CompileError,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    RuntimeError,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way we can return the actual value instead of printing it, and indicate that everything is OK at the same time, kinda like Rust&amp;rsquo;s &lt;code&gt;Option&lt;/code&gt; type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// switch(opcode) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;           .Ret =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; .{ .OK = self.pop() },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way we can check the results in our VM tests.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve omitted a bunch of stuff from this chapter, but simply because there aren&amp;rsquo;t many interesting things there when it comes to Zig vs C.
But one thing I would like to return to is metaprogramming, because this book does it frequently enough to be a hassle.
We&amp;rsquo;ve already seen a bunch of &lt;code&gt;#define&lt;/code&gt; directives in the C examples above, and the book goes pretty far with them, defining a polymorphic &lt;code&gt;BINARY_OP&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define BINARY_OP(op) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    do { \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;      double b = pop(); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;      double a = pop(); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;      push(a op b); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    } while (false)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;do {...} while(false)&lt;/code&gt; is a common trick in C macros.
For those unfamiliar with how &lt;code&gt;do while&lt;/code&gt; works, as it is rarely seen in other languages, it executes the body first, then checks the condition and repeats if it is true.
Classical &lt;code&gt;while&lt;/code&gt; checks the condition first.
Most languages omit &lt;code&gt;do while&lt;/code&gt; because it is essentially the same as writing the body of the while loop two times, e.g.:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo();           &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// do {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (test()) { &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;//    foo();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    foo();       &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// } while (test());
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, there are other ways to rewrite this code, and &lt;code&gt;do while&lt;/code&gt; looks clearer, but it&amp;rsquo;s quite rare.
In our case though, it is used as a way to introduce a valid language construct that allows for a semicolon to be inserted after it.
Because of that, it uses &lt;code&gt;while(false)&lt;/code&gt; i.e. it never loops.&lt;/p&gt;
&lt;p&gt;So when you write &lt;code&gt;BINARY_OP(+);&lt;/code&gt; (mind the semicolon) it expands to the correct code with a semicolon after &lt;code&gt;while (false);&lt;/code&gt; which is required in the case of this language construct, unlike with other loops.
Yep, that&amp;rsquo;s the sole reason it is used here, and compilers are smart enough to detect that the loop will never happen, so they omit the loop entirely.
A truly sad state of metaprogramming, and expression statements in C.&lt;/p&gt;
&lt;p&gt;However, Zig doesn&amp;rsquo;t have macros.
Instead, it has the &lt;code&gt;comptime&lt;/code&gt; keyword, which marks the expression or function argument to be used only at compilation time.
Unfortunately, there doesn&amp;rsquo;t seem to be a way to write an inline comptime function that will accept an operator and return some kind of AST, or other code to be present in the expression.
We can work around it, though:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; binaryOp(op: OPCode, a: Value, b: Value) Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (op) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Add =&amp;gt; a + b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Sub =&amp;gt; a - b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Mul =&amp;gt; a * b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Div =&amp;gt; a / b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ---8&amp;lt;---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;//       switch(opcode) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;                .Add, .Sub, .Mul, .Div =&amp;gt; |instr| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; b = self.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; sp = self.stack_top - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    sp[0] = binaryOp(instr, sp[0], b);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not as pretty, but works, I guess.
We do have a cost of doing branching twice, e.g. first in the &lt;code&gt;run&lt;/code&gt; function, then in the &lt;code&gt;binaryOp&lt;/code&gt; function, even though by the time we&amp;rsquo;re in &lt;code&gt;binaryOp&lt;/code&gt; we already know what operation we&amp;rsquo;re dealing with.
C&amp;rsquo;s macros are giving us the ability to construct code without explicit copy-pasting and without explicit re-branching.
We can avoid re-branching by writing it like this, of course:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; add(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; b = self.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; sp = self.stack_top - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sp[0] = sp[0] + b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; sub(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; b = self.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; sp = self.stack_top - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sp[0] = sp[0] - b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; div(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; b = self.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; sp = self.stack_top - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sp[0] = sp[0] / b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; mul(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; b = self.pop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; sp = self.stack_top - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sp[0] = sp[0] * b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; run(self: *Self) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (opcode) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;                .Add =&amp;gt; self.add(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Sub =&amp;gt; self.sub(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Mul =&amp;gt; self.mul(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Div =&amp;gt; self.div(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But now you see clearly what parts of the code can be easily generated, all these functions only differ by their name.
Unfortunately, Zig&amp;rsquo;s &lt;code&gt;comptime&lt;/code&gt; isn&amp;rsquo;t capable of treating operators as values, so we can&amp;rsquo;t write something like &lt;code&gt;self.binaryOp(-)&lt;/code&gt; and handle it at compilation time to produce the body.
Oh well, Lisp macros have spoiled me, I guess.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s like the only part I have an issue with in this language.
The author is very vocal about macros, but after speaking with them on IRC a few times it seems to me that they only saw C macros and, maybe, C++ templates, and were like: &amp;ldquo;Yikes, macros are bad!&amp;rdquo;.
We&amp;rsquo;ve been manipulating code as data with macros since the 60s, people did a lot of research creating safer ways to write macros, then the C preprocessor comes along and now everybody shits on macros because text substitutions are bad.
Of course, they are!
What baffles me the most is that among lispers there are people who are equally vocal about how bad macros are and that you should never write ones.
I guess I&amp;rsquo;ll write another post about that, adding another hit to the horse.&lt;/p&gt;
&lt;h2 id=&#34;scanning-on-demand&#34;&gt;Scanning on Demand&lt;/h2&gt;
&lt;p&gt;This chapter starts painfully.
Well, painfully isn&amp;rsquo;t the right word really, but it introduces a lot of inconvenience by breaking our &lt;code&gt;main&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;At the start of the chapter, we&amp;rsquo;re introduced to two basic workflows our executable will support - run a &lt;abbr title=&#34;Read Eval Print Loop&#34;&gt;&amp;ldquo;REPL&amp;rdquo;&lt;/abbr&gt; or run a file.
And that brings me to my pain point - why doesn&amp;rsquo;t Zig have any kind of a REPL?
Again, I&amp;rsquo;m spoiled by lisps, but it&amp;rsquo;s so liberating to have a broken program, yet still be able to call functions from the REPL, gradually fixing the program.
Here, I&amp;rsquo;m basically stripped of any way to run any code, until I make the whole source work again.
Well, that&amp;rsquo;s the downside of the edit compile run cycle, but lisps are compiled languages that don&amp;rsquo;t have such a problem.
The compilation&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; just happens in the REPL.&lt;/p&gt;
&lt;p&gt;As a matter of fact, the &lt;code&gt;main&lt;/code&gt; function will be broken for the entirety of this chapter.&lt;/p&gt;
&lt;p&gt;This nitpick aside, we&amp;rsquo;re finally starting to work on the parser.
Unfortunately, this chapter isn&amp;rsquo;t interesting on its own, when it comes to implementing this in Zig.
Same tricks with pointers replaced by integers, and pretty much the same code otherwise.&lt;/p&gt;
&lt;p&gt;Still not sure why the chapter required to break &lt;code&gt;main&lt;/code&gt; if we never actually used it.
It will make more sense as the part of second chapter.&lt;/p&gt;
&lt;h2 id=&#34;compiling-expressions&#34;&gt;Compiling Expressions&lt;/h2&gt;
&lt;p&gt;In the spirit of the previous chapter, the breakage continues.
Remember how I said that writing tests during this book will result in lots of test rewriting due to constant refactoring?
This is probably the first, but not the last instance of this - we&amp;rsquo;ve changed the &lt;code&gt;interpret&lt;/code&gt; signature to accept the source code instead of a chunk.&lt;/p&gt;
&lt;p&gt;This broke all of my VM tests, though, thankfully, I only had just one at this point.
Actually, I don&amp;rsquo;t like this change, to be honest, I&amp;rsquo;d much rather preserve the old signature, as the VM interprets the bytecode, not the source code.
The bytecode doesn&amp;rsquo;t have to come from the source code, it can come from anywhere, and hence it should be what the function accepts.
Instead, we create the chunk inside the &lt;code&gt;interpret&lt;/code&gt; function and fill it with the compiler.
Oh well, I&amp;rsquo;m not a language designer proper, so I guess I should not complain.&lt;/p&gt;
&lt;p&gt;Anyway, this chapter is interesting.
We&amp;rsquo;re actually starting to compile our language from source code into bytecode, and that&amp;rsquo;s cool.
The parser itself is quite concise, and I like how it is implemented so far.
One interesting thing I&amp;rsquo;d like to point out is how the book defines the rules:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ParseRule rules[] = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_LEFT_PAREN]    = {grouping, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_RIGHT_PAREN]   = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_LEFT_BRACE]    = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_RIGHT_BRACE]   = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_COMMA]         = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_DOT]           = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_MINUS]         = {unary,    binary, PREC_TERM},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_PLUS]          = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     binary, PREC_TERM},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_SEMICOLON]     = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_SLASH]         = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     binary, PREC_FACTOR},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_STAR]          = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     binary, PREC_FACTOR},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_BANG]          = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_NUMBER]        = {number,   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  [TOKEN_ERROR]         = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [TOKEN_EOF]           = {&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;NULL&lt;/span&gt;,   PREC_NONE},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;static&lt;/span&gt; ParseRule* &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;getRule&lt;/span&gt;(TokenType type) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &amp;amp;rules[type];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is when C looks nice and beautiful (if you can say so).
The fact that enumerations in C are just numbers has a lot of problems, but sometimes it&amp;rsquo;s cool because you can use them as array indexes.&lt;/p&gt;
&lt;p&gt;As for Zig, I couldn&amp;rsquo;t find if it has a way to do the same thing.
Mainly because you can&amp;rsquo;t initialize an array using enumeration tags as indexes.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;zig translate-c&lt;/code&gt; on this simplified example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TOKEN_RIGHT_PAREN,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TOKEN_LEFT_BRACE,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TOKEN_RIGHT_BRACE,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TOKEN_COMMA,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TOKEN_DOT,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} TokenType;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PREC_A,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PREC_B,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PREC_C,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PREC_D,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} Precedence;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Precedence precedence;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} ParseRule;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ParseRule rules[] = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [TOKEN_LEFT_BRACE]    = {PREC_A},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [TOKEN_DOT]           = {PREC_B},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [TOKEN_RIGHT_BRACE]   = {PREC_C},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [TOKEN_RIGHT_PAREN]   = {PREC_D},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get the following Zig code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// .. tons of definitions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TOKEN_RIGHT_PAREN: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TOKEN_LEFT_BRACE: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TOKEN_RIGHT_BRACE: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TOKEN_COMMA: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TOKEN_DOT: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 4;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; TokenType = &lt;span style=&#34;font-weight:bold&#34;&gt;c_uint&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; PREC_A: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; PREC_B: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; PREC_C: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; PREC_D: &lt;span style=&#34;font-weight:bold&#34;&gt;c_int&lt;/span&gt; = 3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Precedence = &lt;span style=&#34;font-weight:bold&#34;&gt;c_uint&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; ParseRule = &lt;span style=&#34;font-weight:bold&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    precedence: Precedence,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; rules: [5]ParseRule = [5]ParseRule{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ParseRule{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .precedence = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;c_uint&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(PREC_D)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ParseRule{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .precedence = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;c_uint&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(PREC_A)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ParseRule{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .precedence = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;c_uint&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(PREC_C)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;std&amp;#34;&lt;/span&gt;).mem.zeroes(ParseRule),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ParseRule{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .precedence = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;c_uint&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(PREC_B)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// .. tons of more definitions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looks like Zig doesn&amp;rsquo;t have a syntax like that, suggested by the fact that it sorted elements of the array based on the enumeration tag values.
But that practically removes any benefits of using enumerations in such a way, as we&amp;rsquo;re forced to keep the order ourselves.
Perhaps, there&amp;rsquo;s a way to do that using &lt;code&gt;comptime&lt;/code&gt;, but I&amp;rsquo;m not that good with Zig.
So, I did it like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; makeRules() []ParseRule {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; r = [_]ParseRule{&lt;span style=&#34;font-weight:bold&#34;&gt;undefined&lt;/span&gt;} ** &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeInfo&lt;/span&gt;(TokenType).Enum.fields.len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.LEFT_PAREN)] = .{ .prefix = Parser.grouping, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .CALL };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.RIGHT_PAREN)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.LEFT_BRACE)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.RIGHT_BRACE)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.COMMA)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.DOT)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.MINUS)] = .{ .prefix = Parser.unary, .infix = Parser.binary, .precedence = .TERM };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.PLUS)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = Parser.binary, .precedence = .TERM };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.SEMICOLON)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.SLASH)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = Parser.binary, .precedence = .FACTOR };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.STAR)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = Parser.binary, .precedence = .FACTOR };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.BANG)] = .{ .prefix = Parser.unary, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.NUMBER)] = .{ .prefix = Parser.number, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.ERROR)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(TokenType.EOF)] = .{ .prefix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .infix = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, .precedence = .NONE };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &amp;amp;r;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; rules = makeRules();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; getRule(t: TokenType) ParseRule {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; rules[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(t)];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works, looks awful.&lt;/p&gt;
&lt;p&gt;Apart from that, the chapter is pretty straightforward.
Another thing I want to point out is the fact that C supports compilation flags out of the box, and Zig doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Well, in C it is a hot mess, but it works reliably enough to see it as a feature in my opinion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define DEBUG_PRINT_CODE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// later in the code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#ifdef DEBUG_PRINT_CODE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// compile-time code injection
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, when compiling the code, you can supply &lt;code&gt;-DDEBUG_PRINT_CODE&lt;/code&gt; to the compiler and it will set this to &lt;em&gt;something&lt;/em&gt; so the &lt;code&gt;#ifdef&lt;/code&gt; directive contents will be included in the resulting source code.&lt;/p&gt;
&lt;p&gt;In Zig, there&amp;rsquo;s again &lt;code&gt;comptime&lt;/code&gt; and I guess writing &lt;code&gt;if (comptime DEBUG_PRINT_CODE) { ... }&lt;/code&gt; would include/eliminate the code at compile time, but how do we supply it to the compiler?
The answer is the build system of Zig, which itself is just a program written in Zig.
And again, I feel that this is way too complicated than it should be, especially since I have tests in a separate directory, and I have to pass compilation options to tests as well as to the main executable.
I didn&amp;rsquo;t bother with that in the end.&lt;/p&gt;
&lt;p&gt;Finally, &lt;em&gt;challenges&lt;/em&gt;.
This chapter has a decent set of &lt;em&gt;challenges&lt;/em&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, except for the last one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;You might be wondering about complex “mixfix” expressions that have more than two operands separated by tokens.
C’s conditional or “ternary” operator, &lt;code&gt;?:&lt;/code&gt;, is a widely known one.&lt;/p&gt;
&lt;p&gt;Add support for that operator to the compiler.
You don’t have to generate any bytecode, just show how you would hook it up to the parser and handle the operands.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, no - why would you need to implement &lt;code&gt;?:&lt;/code&gt; before we have implemented &lt;code&gt;if&lt;/code&gt; itself?
Second - why implement &lt;code&gt;?:&lt;/code&gt; at all if we&amp;rsquo;re implementing the new language and can make &lt;code&gt;if&lt;/code&gt; to be an expression?
I understand that this is a small and simple language, but the &lt;code&gt;if&lt;/code&gt; expressions can be a great way to introduce people to the concept of familiar statements being expressions as well.&lt;/p&gt;
&lt;h2 id=&#34;types-of-values&#34;&gt;Types of Values&lt;/h2&gt;
&lt;p&gt;This chapter begins with a paragraph I can connect with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The nice thing about working in C is that we can build our data structures from the raw bits up.
The bad thing is that we have to do that.
C doesn’t give you much for free at compile time and even less at runtime.
As far as C is concerned, the universe is an undifferentiated array of bytes.
It’s up to us to decide how many of those bytes to use and what they mean.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Indeed, when I was working with C this was always the case.
On one hand, it&amp;rsquo;s problematic, on the other, it is empowering.
But I&amp;rsquo;m doing this book&amp;rsquo;s project in Zig and I can&amp;rsquo;t say that Zig is the same as C in this regard.
Instead of doing things the C way, Zig provides more high-level concepts to us, like union enums, and such.
So let&amp;rsquo;s try to use these instead.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how we implement the &lt;code&gt;Value&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; print(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Number =&amp;gt; |value| std.debug.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{d}&amp;#34;&lt;/span&gt;, .{value}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Bool =&amp;gt; |value| std.debug.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;, .{value}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Nil =&amp;gt; std.debug.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nil&amp;#34;&lt;/span&gt;, .{}),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In its essence, it&amp;rsquo;s similar to the union in the book:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  VAL_BOOL,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  VAL_NIL,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  VAL_NUMBER,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} ValueType;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ValueType type;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; boolean;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt; number;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } as;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} Value;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, as an added bonus, we can add methods to our &lt;code&gt;Value&lt;/code&gt; type, the same as with other &lt;code&gt;struct&lt;/code&gt;&amp;rsquo;s.
As you can see, the &lt;code&gt;print&lt;/code&gt; function is a part of the &lt;code&gt;union(enum)&lt;/code&gt; and can be invoked as &lt;code&gt;val.print()&lt;/code&gt; later in the code.&lt;/p&gt;
&lt;p&gt;Once again, we have to change parts of our code that are quite basic, but nothing too breaking this time.
All I had to do was wrap numbers into the &lt;code&gt;Value&lt;/code&gt; constructor in a few tests.
This is just the beginning though, we have to make more &lt;code&gt;Value&lt;/code&gt; sub-types for strings, and objects.&lt;/p&gt;
&lt;h2 id=&#34;strings&#34;&gt;Strings&lt;/h2&gt;
&lt;p&gt;Now, this is where my previous attempt at this book in Zig train-wrecked.
Or, should I say, it was the beginning of the end for that implementation.
You see, til now, most concepts introduced by the book were easy enough to translate from C to Zig, because most of the time the stuff was either the same or already backed by Zig&amp;rsquo;s standard library.
For example, at the start of the book, I decided not to implement dynamic arrays, because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I already made my fair share of dynamic arrays in C back when I was a C programmer&lt;/li&gt;
&lt;li&gt;After looking at what the book suggests, and the implementation in Zig&amp;rsquo;s standard library, they&amp;rsquo;re practically the same, with some small changes that are irrelevant for the matter.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Other stuff was pretty much the same, except for, perhaps, how pointers are used - instead I used offsets most of the time, as it is easier to do.
Unions and enumerations are again similar, though with some small differences, like being able to use &lt;code&gt;union(enum)&lt;/code&gt; and add methods onto it, but again, C code kinda does the same thing, just &lt;em&gt;the C way&lt;/em&gt;.
Strings, however, are a different beast.
They&amp;rsquo;re objects, and hence they&amp;rsquo;re dynamically typed because objects kinda are.
E.g. in Lox string is an object, a function is also an object, and a class also is an object, and we have to express this idea somehow in C/Zig.
Here&amp;rsquo;s how the book does it in C:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  OBJ_STRING,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} ObjType;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Obj {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ObjType type;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is only a &lt;code&gt;struct&lt;/code&gt; definition for the object type, but there&amp;rsquo;s a certain trick that we can do in C by abusing the fact that structure layouts are consistent.
We can create a second structure like this one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; ObjString {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Obj obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; length;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;* chars;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, here&amp;rsquo;s an interesting part - we can convert a pointer between these two structs at will!
It is possible because the memory layout between the first field in the &lt;code&gt;ObjString&lt;/code&gt; and the entirety of &lt;code&gt;Obj&lt;/code&gt; &lt;code&gt;struct&lt;/code&gt; is the same.
Now, since the first field in the &lt;code&gt;struct&lt;/code&gt; has the same address as the &lt;code&gt;struct&lt;/code&gt; itself, i.e. an offset of &lt;code&gt;0&lt;/code&gt;, and the &lt;code&gt;struct&lt;/code&gt; field size is the same as its type, given the pointer to &lt;code&gt;ObjString&lt;/code&gt; we can cast it to &lt;code&gt;Obj&lt;/code&gt; and read its fields as normal.&lt;/p&gt;
&lt;p&gt;But how do we do that in Zig?
Zig&amp;rsquo;s structs are much more than C structs, as they can have methods, we can manipulate field types at compile time, and so on.
My first approach was like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; LoxString = []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; LoxObject = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    next: ?*LoxObject,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    data: &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        String: LoxString,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; objType(self: LoxObject) Tag(LoxObject) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; activeTag(self.data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isString(self: LoxObject) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (self.data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .String =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; allocString(s: LoxString, vm: *VM(Code), allocator: Allocator) *LoxObject {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; obj = allocator.create(LoxObject) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt; exit(123, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Not enough memory to allocate object&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (obj.*.data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .String =&amp;gt; |*value| value.* = s,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        obj.next = vm.objects;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vm.objects = obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; freeObject(obj: *LoxObject, allocator: Allocator) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (obj.*.data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .String =&amp;gt; |s| allocator.free(s),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        allocator.destroy(obj);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, I decided to store the underlying data of the object in the &lt;code&gt;union(enum)&lt;/code&gt;, similarly to how I do that for &lt;code&gt;Value&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Obj: *Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Later, when we added more object types, this became a problem.
This layout means that I can&amp;rsquo;t cast the &lt;code&gt;LoxObject&lt;/code&gt; to a &lt;code&gt;LoxString&lt;/code&gt;, and I can&amp;rsquo;t really access it without going through the union:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;test&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;string concatenation&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; vm = VM(Code).init(allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; vm.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (interpret(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; + &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, &amp;amp;vm).OK) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .Obj =&amp;gt; |obj| &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (obj.*.data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .String =&amp;gt; |s| expectEqualSlices(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, s, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ab&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code was filled with these &lt;code&gt;obj.*.data&lt;/code&gt; switches, that extracted the string.
And later on, at some point, I had really weird bugs, like when my &lt;code&gt;isString&lt;/code&gt; function returns &lt;code&gt;true&lt;/code&gt;, but when I try to access the string, I get the error &amp;ldquo;trying to access the inactive field of enumeration&amp;rdquo;.
Be it a bug in Zig itself or in my code I don&amp;rsquo;t care.&lt;/p&gt;
&lt;p&gt;Since then I changed the implementation to be more like in the book:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;50
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Type = &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    String,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Obj = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    objType: Type,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    next: ?*Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; allocate(vm: *VM, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;, objType: Type) *Obj {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; ptr = vm.allocator.create(T) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Common.exit(200, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t allocate object&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ptr.obj = Obj{ .objType = objType, .next = vm.objects };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vm.objects = &amp;amp;ptr.obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &amp;amp;ptr.obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asString(self: *Obj) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@fieldParentPtr&lt;/span&gt;(String, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;, self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; destroy(self: *Obj, vm: *VM) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (self.objType) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .String =&amp;gt; self.asString().destroy(vm),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; String = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    obj: Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bytes: []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; create(vm: *VM, bytes: str) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; obj = Obj.allocate(vm, String, .String);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; out = obj.asString();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        out.* = String{ .obj = obj.*, .bytes = bytes };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; out;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; copy(vm: *VM, source: str) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; buffer = vm.allocator.alloc(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, source.len) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Common.exit(200, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t allocate string&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        std.mem.copy(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, buffer, source);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; String.create(vm, buffer);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; destroy(self: *String, vm: *VM) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vm.allocator.free(self.bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vm.allocator.destroy(self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Now, this &lt;code&gt;@fieldParentPtr&lt;/code&gt; feels sketchy with its &lt;code&gt;&amp;quot;obj&amp;quot;&lt;/code&gt; parameter.
It is supposed to be a field name, and I find string a weird choice as strings can contain arbitrary data, while field names can&amp;rsquo;t.
But that&amp;rsquo;s beside the point, let&amp;rsquo;s look at it a bit closer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asString(self: *Obj) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@fieldParentPtr&lt;/span&gt;(String, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;, self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The signature of this &lt;em&gt;builtin&lt;/em&gt; is as follows: &lt;code&gt;comptime ParentType: type&lt;/code&gt;, &lt;code&gt;comptime field_name: []const u8&lt;/code&gt;, &lt;code&gt;field_ptr: *T&lt;/code&gt;, and the return type is a pointer to the &lt;code&gt;ParentType&lt;/code&gt;.
As you can see, the usage is interesting - we pass the desired type &lt;code&gt;String&lt;/code&gt; which is a different &lt;code&gt;struct&lt;/code&gt;.
Then we pass the &lt;code&gt;&amp;quot;obj&amp;quot;&lt;/code&gt; field name, and the last parameter should be a pointer to a field, for which we use the object pointer itself.&lt;/p&gt;
&lt;p&gt;Presumably, Zig knows its memory layout and can calculate the offset to the base &lt;code&gt;struct&lt;/code&gt; given a field pointer.
Indeed, knowing the layout and giving a pointer to a field, it is possible to calculate the start of the struct, however, in this case, we do it a bit weird, as we get a pointer to the &lt;code&gt;Obj&lt;/code&gt; structure, which doesn&amp;rsquo;t have the &lt;code&gt;obj&lt;/code&gt; field at all.
We then use this pointer as a third parameter, i.e. as a pointer to the field of the &lt;code&gt;String&lt;/code&gt; structure.
Therefore, this built-in calculates the width of the &lt;code&gt;obj&lt;/code&gt; field, subtracts it from the pointer address, and returns the pointer to the &lt;code&gt;base struct&lt;/code&gt; but as the &lt;code&gt;String&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;Overall, this looks like what we do in C, except we use &lt;code&gt;@fieldParentPtr&lt;/code&gt; to do the pointer casting.
We can see it being used in the &lt;code&gt;create&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; create(vm: *VM, bytes: str) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; obj = Obj.allocate(vm, String, .String);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; out = obj.asString();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        out.* = String{ .obj = obj.*, .bytes = bytes };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; out;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;We have the object allocated as a &lt;code&gt;String&lt;/code&gt;, ensuring the memory layout, but then we assign the &lt;code&gt;.obj&lt;/code&gt; field an &lt;code&gt;Obj&lt;/code&gt; structure, finally returning a pointer to this field:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; allocate(vm: *VM, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;, objType: Type) *Obj {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; ptr = vm.allocator.create(T) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Common.exit(200, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t allocate object&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ptr.obj = Obj{ .objType = objType, .next = vm.objects };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vm.objects = &amp;amp;ptr.obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &amp;amp;ptr.obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Everything should now make sense - we indeed have the pointer to the &lt;code&gt;obj&lt;/code&gt; field by the time we get to use the &lt;code&gt;asString&lt;/code&gt; function, but we always have the pointer to the &lt;code&gt;Obj&lt;/code&gt; at hand.&lt;/p&gt;
&lt;p&gt;In other words, it&amp;rsquo;s not as in C where we literally convert a single pointer between two different layouts, abusing the fact that the memory layout allows for it.
Instead, we can have a pointer to anywhere inside the struct and still get the correct parent pointer thanks to the known memory layout.
We could do the same in C but it would be more work, and far more error-prone, as we would need to compute this offset manually.
Here, Zig has us covered.&lt;/p&gt;
&lt;p&gt;Overall, I like this approach more, I guess.
C&amp;rsquo;s way of doing this feels like a clever memory trick, while Zig&amp;rsquo;s way of doing this is more of a compiler-supported way.&lt;/p&gt;
&lt;h2 id=&#34;hash-tables&#34;&gt;Hash Tables&lt;/h2&gt;
&lt;p&gt;Now, in my previous attempt I thought to myself: &amp;ldquo;Well, I skipped the dynamic array, let&amp;rsquo;s at least implement a hash table&amp;rdquo;.
As a result, I ended up looking at how the hash table is implemented in Zig&amp;rsquo;s standard library.
Now, I&amp;rsquo;m not sure if my implementation was correct, but it seemed that way.&lt;/p&gt;
&lt;p&gt;Looking at it now, I&amp;rsquo;m not sure if I could use a hash table from Zig&amp;rsquo;s standard library, as it needs custom hashing.
I probably can implement some kind of interface for the objects that would allow me to hash them.
So let&amp;rsquo;s look into that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// General purpose hash table.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// No order is guaranteed and any modification invalidates live iterators.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// It provides fast operations (lookup, insertion, deletion) with quite high
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// load factors (up to 80% by default) for low memory usage.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// For a hash map that can be initialized directly that does not store an Allocator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// field, see `HashMapUnmanaged`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// If iterating over the table entries is a strong usecase and needs to be fast,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// prefer the alternative `std.ArrayHashMap`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// Context must be a struct type with two member functions:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;///   hash(self, K) u64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;///   eql(self, K, K) bool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// Adapted variants of many functions are provided.  These variants
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// take a pseudo key instead of a key.  Their context must have the functions:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;///   hash(self, PseudoKey) u64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;///   eql(self, PseudoKey, K) bool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; HashMap(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; K: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; V: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; Context: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; max_load_percentage: &lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OK, so the documentation of &lt;code&gt;std.hash_map.HashMap&lt;/code&gt; says that we can pass a &lt;code&gt;Context&lt;/code&gt; that has the &lt;code&gt;hash&lt;/code&gt; and &lt;code&gt;eql&lt;/code&gt; functions.
That should do it.&lt;/p&gt;
&lt;p&gt;Speaking of reusing the standard library - Zig already has the &amp;ldquo;FNV-1a&amp;rdquo; algorithm the book implements as a part of &lt;code&gt;std.hash.Fnv1a_32&lt;/code&gt;.
So we&amp;rsquo;re going to reuse it too.&lt;/p&gt;
&lt;p&gt;After walking through the chapter, here&amp;rsquo;s the final table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; table_max_load = 75;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Table = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    hm: HashMap(*String, Value, Ctx, table_max_load),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Ctx = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; hash(_: Ctx, key: *String) &lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(key.*.hash);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; eql(_: Ctx, key_a: *String, key_b: *String) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; key_a.*.hash == key_b.*.hash &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                std.mem.eql(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, key_a.*.bytes, key_b.*.bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; init(allocator: Allocator) Table {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Table{ .hm = HashMap(*String, Value, Ctx, table_max_load).init(allocator) };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; deinit(self: *Table) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.hm.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; findString(self: *Table, chars: str, hash: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) ?*String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.hm.getKey(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@constCast&lt;/span&gt;(&amp;amp;String{ .obj = &lt;span style=&#34;font-weight:bold&#34;&gt;undefined&lt;/span&gt;, .hash = hash, .bytes = chars }));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; set(self: *Table, key: *String, value: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.hm.fetchPut(key, value) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            common.exit(205, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t put the key to a table&amp;#34;&lt;/span&gt;, .{})) |_|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// key is not new
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; get(self: *Table, key: *String) ?Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.hm.get(key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; delete(self: *Table, key: *String) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.hm.remove(key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Someone would say that that&amp;rsquo;s cheating.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;While yes, I&#39;m not doing what the book suggests, I already have done that before.&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; table_max_load = 0.75;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Entry = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    key: ?*LoxObject,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    value: Value,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; growCapacity(capacity: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; ((capacity) &amp;lt; 8) 8 &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; capacity * 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Table = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entries: []Entry,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    capacity: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    allocator: Allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    count: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; init(allocator: Allocator) Table {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Table{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .allocator = allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .entries = &amp;amp;[_]Entry{},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .capacity = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .count = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; allocatedSlice(self: *Table) []Entry {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.entries.ptr[0..self.capacity];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; deinit(self: *Table) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.allocator.free(self.allocatedSlice());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; findEntry(entries: []Entry, capacity: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, key: *LoxObject) *Entry {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; hash = &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (key.data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .String =&amp;gt; |s| s.hash,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; index = hash % capacity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; tombstone: ?*Entry = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; entry = &amp;amp;entries[index];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key == &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.value.isNil()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (tombstone) |t| t &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; entry;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (tombstone == &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) tombstone = entry;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key == key) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; entry;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            index = (index + 1) % capacity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; findString(self: *Table, chars: []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, hash: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) ?*LoxObject {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.count == 0) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; index = hash % self.capacity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; entries = self.entries;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; entry = entries[index];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key) |k| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (k.data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    .String =&amp;gt; |s| s.hash == hash &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        std.mem.eql(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, s.chars, chars),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; entry.key;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.value.isNil()) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            index = (index + 1) % self.capacity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; adjustCapacity(self: *Table, capacity: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; new_memory = self.allocator.alloc(Entry, capacity) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            common.exit(48, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t allocate memory for the hash table&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (new_memory) |*entry| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            entry.key = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            entry.value = Nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.count = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (self.entries) |*entry| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key) |key| {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; dest = findEntry(new_memory, capacity, key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                dest.key = entry.key;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                dest.value = entry.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                self.count += 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.allocator.free(self.allocatedSlice());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.entries = new_memory;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.capacity = capacity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; tableAddAll(from: *Table, to: *Table) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; i = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (i &amp;lt; from.capacity) : (i += 1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; entry = &amp;amp;from.entries[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key != &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                to.tableSet(entry.key, entry.value);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; set(self: *Table, key: *LoxObject, value: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.count + 1 &amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@floatToInt&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intToFloat&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;f32&lt;/span&gt;, self.capacity) * table_max_load)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; capacity = growCapacity(self.capacity);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.adjustCapacity(capacity);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; entry = findEntry(self.entries, self.capacity, key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; is_new = entry.key == &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (is_new &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; entry.value.isNil()) self.count += 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        entry.key = key;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        entry.value = value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; is_new;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; get(self: *Table, key: *LoxObject) ?Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.count == 0) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; entry = findEntry(self.entries, self.capacity, key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key == &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; entry.value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; delete(self: *Table, key: *LoxObject) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.count == 0) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; entry = findEntry(self.entries, self.capacity, key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (entry.key == &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        entry.key = &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        entry.value = True;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;I just don&amp;rsquo;t feel like doing it again.&lt;/p&gt;
&lt;p&gt;And, I would like to learn how to use Zig&amp;rsquo;s own hash tables, so this is a perfect opportunity.
The use of &lt;code&gt;Context&lt;/code&gt; is interesting - thanks to it we can implement the hashing however we want.&lt;/p&gt;
&lt;p&gt;The only thing I don&amp;rsquo;t like in the new solution is the &lt;code&gt;@constCast&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; findString(self: *Table, chars: str, hash: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) ?*String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.hm.getKey(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@constCast&lt;/span&gt;(&amp;amp;String{ .obj = &lt;span style=&#34;font-weight:bold&#34;&gt;undefined&lt;/span&gt;, .hash = hash, .bytes = chars }));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This function itself is a bit hacky, as we only mimic the key object by creating it on a stack.
Alternatively, I could use the &lt;code&gt;getKeyAdapted&lt;/code&gt;, and provide it a context that does a lookup of a fake key:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// after &amp;#39;const Ctx = struct { ... };&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; AdaptedCtx = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        h: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        b: str,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; init(b: str, h: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) AdaptedCtx {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; AdaptedCtx{ .b = b, .h = h };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; hash(self: AdaptedCtx, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; _: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;)) &lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.h);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; eql(self: AdaptedCtx, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; _: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;), key: *String) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.h == key.*.hash &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                std.mem.eql(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, self.b, key.*.bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Now we can change &lt;code&gt;findString&lt;/code&gt; to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;45
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; findString(self: *Table, chars: str, hash: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) ?*String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.hm.getKeyAdapted(&lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, AdaptedCtx.init(chars, hash));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I don&amp;rsquo;t really like it either, and I don&amp;rsquo;t know which one is better/more idiomatic.
But, other than that, the new version is nice and clear.&lt;/p&gt;
&lt;h2 id=&#34;global-variables&#34;&gt;Global Variables&lt;/h2&gt;
&lt;p&gt;Here we go again.
By the end of this chapter, all tests will be broken.
Again.&lt;/p&gt;
&lt;p&gt;I mean, I&amp;rsquo;m glad I write tests, as Zig privies a test allocator that acts like &lt;a href=&#34;https://valgrind.org/&#34; target=&#34;_blank&#34;&gt;Valgrind&lt;/a&gt; and I had noticed a couple of memory leaks.
Not because the book has them, but just because I was careless and forgot to clean up some values.&lt;/p&gt;
&lt;p&gt;However, now no VM test is passing.
Why is that?
Because this chapter introduced statements, and now if you write any expression you must end it with a semicolon, thus turning it into a statement.
And statements are known for not returning anything.
Hence the &lt;code&gt;interpret&lt;/code&gt; function now can&amp;rsquo;t return anything, and therefore I can&amp;rsquo;t test for anything.
Amazing!&lt;/p&gt;
&lt;p&gt;Now, there are ways of working this around but all of these are hacky.
I think the proper solution would be to introduce a top-level &lt;code&gt;return&lt;/code&gt; statement, so we could return any expression from the top level.
And it&amp;rsquo;s a shame - the book mentions the REPL four times during this chapter, saying how useful something would be in the context of one.
However, it completely disregards the fact that REPL stands for Read Eval &lt;strong&gt;Print&lt;/strong&gt; Loop, and in our case, we can&amp;rsquo;t really print anything in the REPL, because now everything is a statement.
Welp.&lt;/p&gt;
&lt;p&gt;What I like about Lox is that the syntax for declaring a variable requires a keyword.
This is one of the reasons I dislike languages like Python - looking at the assignment you can&amp;rsquo;t guess if you&amp;rsquo;re creating a new variable or assigning an existing one.
Paired with the absence of scopes, we get this horrible thing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        a = 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print&lt;/span&gt;(a)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why is &lt;code&gt;a&lt;/code&gt; available outside the scope of the &lt;code&gt;if&lt;/code&gt; statement?
Because there&amp;rsquo;s only one scope&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; - the function scope.&lt;/p&gt;
&lt;p&gt;Lua is also guilty of this - assigning a non-existent variable creates a &lt;strong&gt;global&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      a = 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   print(a)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But at least it is global, and you can avoid this behavior by using a &lt;code&gt;local&lt;/code&gt; keyword.
Something that all of the Lua code should really do, that&amp;rsquo;s why Fennel uses &lt;code&gt;local&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;JavaScript also had this problem, but then they introduced the &lt;code&gt;let&lt;/code&gt; keyword.
It&amp;rsquo;s still weird because &lt;code&gt;let&lt;/code&gt; variables are &amp;ldquo;hoisted&amp;rdquo; - their logical position of definition is the top of their enclosing scope.
It&amp;rsquo;s not as bad as it sounds, e.g. you can&amp;rsquo;t do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt; f() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    console.log(x) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Error: can&amp;#39;t access lexical declaration &amp;#39;x&amp;#39; before initialization
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; x = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But you can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt; f() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt; g() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    console.log(x) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// a closure? to what?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; x = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  g()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f() &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// prints 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I&amp;rsquo;m getting ahead of the book.
The next chapter is on local variables and scope, so let&amp;rsquo;s see how Lox handles them.&lt;/p&gt;
&lt;h2 id=&#34;local-variables&#34;&gt;Local Variables&lt;/h2&gt;
&lt;p&gt;And to be honest, it&amp;rsquo;s not bad.
Lox handles local variables pretty much the same way as most other languages I have used.
The only nitpick I have is this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; a = 20;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; a = 30; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Error at &amp;#39;a&amp;#39;: Already a variable with this name in this scope.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I don&amp;rsquo;t like this.
In Clojure, that&amp;rsquo;s the norm, because there&amp;rsquo;s no way to set a new value to an already established binding.
So you can overshadow it with a different value.&lt;/p&gt;
&lt;p&gt;Rust also allows shadowing, and I think that&amp;rsquo;s a good feature to have.
Sometimes you want to keep the name but change the type.
The Rust book has this &lt;a href=&#34;https://doc.rust-lang.org/stable/book/ch03-01-variables-and-mutability.html#shadowing&#34; target=&#34;_blank&#34;&gt;example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; spaces = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;   &amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; spaces = spaces.len();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, this can&amp;rsquo;t be done using mutability, because of the type system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;mut&lt;/span&gt; spaces = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;   &amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;spaces = spaces.len();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;The error says we’re not allowed to mutate a variable’s type:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cargo run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Compiling variables v0.1.0 (file:///projects/variables)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error[E0308]: mismatched types
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; --&amp;gt; src/main.rs:3:14
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 |     let mut spaces = &amp;#34;   &amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |                      ----- expected due to this value
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 |     spaces = spaces.len();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |              ^^^^^^^^^^^^ expected `&amp;amp;str`, found `usize`
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;For more information about this error, try `rustc --explain E0308`.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error: could not compile `variables` due to previous error
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lox, however, is dynamically typed, so this can be done using mutability, and that may be a reason to disallow overshadowing.
Still, I would prefer variables that are constant, and overshadowing instead of assignments.&lt;/p&gt;
&lt;h2 id=&#34;jumping-back-and-forth&#34;&gt;Jumping Back and Forth&lt;/h2&gt;
&lt;p&gt;Oh, boy.&lt;/p&gt;
&lt;p&gt;This is a big chapter.
It introduces most of the control flow primitives to the language, in terms of branching, looping, and short-circuiting.
I have a lot to say.&lt;/p&gt;
&lt;h3 id=&#34;if-statements&#34;&gt;If statements&lt;/h3&gt;
&lt;p&gt;First things first, the book introduces the &lt;code&gt;if&lt;/code&gt; statement.
To which I ask - why not introduce an &lt;code&gt;if&lt;/code&gt; expression instead?
&lt;code&gt;if&lt;/code&gt; expressions are very useful, and not that hard to implement, especially in a small language like Lox.
I guess, it&amp;rsquo;s a bit late to do so, as almost everything in Lox grammar builds from the &lt;code&gt;statement&lt;/code&gt; rule, so &lt;code&gt;if&lt;/code&gt; expressions would be out of place.
It&amp;rsquo;s a shame though, as a lot of people don&amp;rsquo;t even know that &lt;code&gt;if&lt;/code&gt; &lt;em&gt;can&lt;/em&gt; be an expression, without being a ternary operator &lt;code&gt;?:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, the &lt;code&gt;if&lt;/code&gt; expression is implemented in an interesting way.
We parse the &lt;code&gt;if&lt;/code&gt; and the condition, and &lt;em&gt;emit&lt;/em&gt; a jump instruction.
Emitting is a bit special we also added a placeholder that we will later patch:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; emitJump(self: *Self, instruction: OPCode) &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(instruction));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(0xff);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(0xff);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.currentChunk().code.items.len)) - 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These two &lt;code&gt;emitByte&lt;/code&gt; calls with &lt;code&gt;0xff&lt;/code&gt; as an argument are exactly for that.&lt;/p&gt;
&lt;p&gt;After the &lt;code&gt;emitJump&lt;/code&gt; step, we parse a statement and then emit another jump instruction.
And right after that, we patch the original jump:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; ifStatement(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.LEFT_PAREN, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;(&amp;#39; after &amp;#39;if&amp;#39;.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.RIGHT_PAREN, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;)&amp;#39; after condition.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; thenJump = self.emitJump(.JumpIfFalse);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.statement();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; elseJump = self.emitJump(.Jump);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.patchJump(thenJump);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.match(.ELSE)) self.statement();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.patchJump(elseJump);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same happens for the &lt;code&gt;elseJump&lt;/code&gt; at the end of the function, if the &lt;code&gt;else&lt;/code&gt; branch is present.&lt;/p&gt;
&lt;p&gt;So, how it works?
The &lt;code&gt;patchJump&lt;/code&gt; function looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; patchJump(self: *Self, offset: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// -2 to adjust for the bytecode for the jump offset itself.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; jump = self.currentChunk().code.items.len - offset - 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (jump &amp;gt; std.math.maxInt(&lt;span style=&#34;font-weight:bold&#34;&gt;u16&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.error_(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Too much code to jump over.&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.currentChunk().code.items[offset] = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;((jump &amp;gt;&amp;gt; 8) &amp;amp; 0xff);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.currentChunk().code.items[offset + 1] = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(jump &amp;amp; 0xff);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Basically, we count how much code we generated by reading the statement after the condition, and patch in the address we need to jump to if the condition was &lt;code&gt;false&lt;/code&gt;.
It&amp;rsquo;s a clever trick.
Notice, the &lt;code&gt;if&lt;/code&gt; statement itself doesn&amp;rsquo;t know anything about scopes - all that is handled by calling the &lt;code&gt;expression&lt;/code&gt; function.
It will kinda be important later.&lt;/p&gt;
&lt;p&gt;Aside from not being an expression, I have no objections to implementing the &lt;code&gt;if&lt;/code&gt; statement this way.
Well, the limitation of &lt;code&gt;65535&lt;/code&gt; opcodes is a bit weird, but if you may remember, the book earlier suggested implementing ways to have more than 256 constants by introducing more instructions that know how to deal with that.
Here, we could also introduce a &lt;code&gt;LongJump&lt;/code&gt; and &lt;code&gt;LongJumpIfFalse&lt;/code&gt; instructions that would handle &lt;code&gt;4294967295&lt;/code&gt; opcodes instead if the body is longer than &lt;code&gt;65535&lt;/code&gt; opcodes.
But this complicates things, and previously it resulted in a lot of misunderstanding where I should and should not take care of such long instructions while I did a first run of the book.
So I won&amp;rsquo;t do it here.&lt;/p&gt;
&lt;p&gt;Now, then there&amp;rsquo;s a &amp;ldquo;Challenge&amp;rdquo;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In addition to &lt;code&gt;if&lt;/code&gt; statements, most C-family languages have a multi-way &lt;code&gt;switch&lt;/code&gt; statement.
Add one to clox.
The grammar is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   switchStmt     &lt;span style=&#34;&#34;&gt;→&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;switch&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt; expression &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; switchCase* defaultCase? &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   switchCase     &lt;span style=&#34;&#34;&gt;→&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;case&amp;#34;&lt;/span&gt; expression &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; statement* ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   defaultCase    &lt;span style=&#34;&#34;&gt;→&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; statement* ;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To execute a &lt;code&gt;switch&lt;/code&gt; statement, first evaluate the parenthesized &lt;code&gt;switch&lt;/code&gt; value expression.
Then walk the cases.
For each case, evaluate its value expression.
If the case value is equal to the &lt;code&gt;switch&lt;/code&gt; value, execute the statements under the case and then exit the switch statement.
Otherwise, try the next case.
If no case matches and there is a &lt;code&gt;default&lt;/code&gt; clause, execute its statements.&lt;/p&gt;
&lt;p&gt;To keep things simpler, we’re omitting fallthrough and &lt;code&gt;break&lt;/code&gt; statements.
Each case automatically jumps to the end of the switch statement after its statements are done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Uh, this isn&amp;rsquo;t how &lt;code&gt;switch&lt;/code&gt; is supposed to work.
The &lt;code&gt;swich&lt;/code&gt; statement is a constant dispatch, meaning cases aren&amp;rsquo;t tried in order, instead, the right one is picked based on the condition.
It can be done with a jump table, or by computing offsets at compile time, and allowing only integer switching and then jumping to the given branch.
That&amp;rsquo;s also a reason why C implements &lt;code&gt;break&lt;/code&gt;, without it the program will continue executing to the next label because labels don&amp;rsquo;t really exist in the program.
This allows for clever tricks like the &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Duff%27s_device&#34; target=&#34;_blank&#34;&gt;Duff&amp;rsquo;s device&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;send(to, from, count)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;register&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;short&lt;/span&gt; *to, *from;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;register&lt;/span&gt; count;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;register&lt;/span&gt; n = (count + 7) / 8;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (count % 8) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 0: &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; { *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 7:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 6:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 5:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 4:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 3:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 2:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; 1:      *to = *from++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (--n &amp;gt; 0);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I do understand that the book tries to keep things easy, but this kind of &lt;code&gt;switch&lt;/code&gt; statement is a useless addition in my opinion.
If Lox had macros, such &lt;code&gt;switch&lt;/code&gt; could be easily implemented in terms of chained &lt;code&gt;if else&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;loops&#34;&gt;Loops&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m skipping over logical operators, as I don&amp;rsquo;t have anything to say about them - they&amp;rsquo;re OK.
Loops, however, are, again, weird.&lt;/p&gt;
&lt;p&gt;First, we have a &lt;code&gt;while&lt;/code&gt; loop, which is probably the only kind of loop any language needs if it doesn&amp;rsquo;t implement tail call elimination/optimization technique.
It is implemented in pretty much the same way as the &lt;code&gt;if&lt;/code&gt; statement, except we emit a &lt;code&gt;Loop&lt;/code&gt; instruction instead.
Again, the design is OK, it is very bare-bones and clean:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; emitLoop(self: *Self, loopStart: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Loop));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; offset = self.currentChunk().code.items.len - loopStart + 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (offset &amp;gt; std.math.maxInt(&lt;span style=&#34;font-weight:bold&#34;&gt;u16&lt;/span&gt;)) self.error_(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Loop body too large.&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;((offset &amp;gt;&amp;gt; 8) &amp;amp; 0xff));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(offset &amp;amp; 0xff));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; whileStatement(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; loopStart: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.currentChunk().code.items.len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.LEFT_PAREN, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;(&amp;#39; after &amp;#39;while&amp;#39;.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.RIGHT_PAREN, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;)&amp;#39; after condition.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; exitJump = self.emitJump(.JumpIfFalse);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.statement();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitLoop(loopStart);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.patchJump(exitJump);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, however, we have a &lt;code&gt;for&lt;/code&gt; loop.
Not only the implementation is much more involved, as it is implemented in terms of the &lt;code&gt;while&lt;/code&gt; loop, but it is also quite useless.
Why?
Because it is a plain old C-style numeric loop.
We already have &lt;code&gt;while&lt;/code&gt;, why do we need &lt;code&gt;for&lt;/code&gt;?
I mean, it&amp;rsquo;s not too hard to translate this into &lt;code&gt;while&lt;/code&gt; loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; i = 0; i &amp;lt; 10; i = i + 1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; i = 0; &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (i &amp;lt; 10) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  i = i + 1; } }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s about the same amount of code.
Yes, I&amp;rsquo;ve used weird formatting on the &lt;code&gt;while&lt;/code&gt; loop example, but only to show that the actual amount of code is about the same.
And that&amp;rsquo;s exactly what the book does in the implementation of the &lt;code&gt;for&lt;/code&gt; loop, except it&amp;rsquo;s this amount of code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; forStatement(self: *Self) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.beginScope();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.consume(.LEFT_PAREN, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;(&amp;#39; after &amp;#39;for&amp;#39;.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.match(.SEMICOLON)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// No initializer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.match(.VAR)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.varDeclaration();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.expressionStatement();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; loopStart: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.currentChunk().code.items.len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; exitJump: &lt;span style=&#34;font-weight:bold&#34;&gt;i32&lt;/span&gt; = -1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!self.match(.SEMICOLON)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.consume(.SEMICOLON, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;;&amp;#39; after loop condition.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Jump out of the loop if the condition is false.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;            exitJump = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.emitJump(.JumpIfFalse));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop)); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Condition.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!self.match(.RIGHT_PAREN)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; bodyJump = self.emitJump(.Jump);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; incrementStart: &lt;span style=&#34;font-weight:bold&#34;&gt;u32&lt;/span&gt; = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.currentChunk().code.items.len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.expression();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.consume(.RIGHT_PAREN, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expect &amp;#39;)&amp;#39; after for clauses.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.emitLoop(loopStart);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            loopStart = incrementStart;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.patchJump(bodyJump);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.statement();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.emitLoop(loopStart);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (exitJump != -1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.patchJump(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(exitJump));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.emitByte(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromEnum&lt;/span&gt;(OPCode.Pop)); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Condition.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.endScope();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, if Lox had macros, the language could define &lt;code&gt;for&lt;/code&gt; in terms of while without all this code.
Macros are special because they allow your language to operate on your code. which may sound complicated, but in actuality is much easier than fiddling with this bytecode generation, as it is more high-level.
Here&amp;rsquo;s an example of a &lt;code&gt;for&lt;/code&gt; macro for Emacs Lisp:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; (,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;progn&lt;/span&gt; ,@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;) ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macroexpand-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 0) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 10) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (let ((a 0))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;   (while (&amp;lt; a 10)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (progn (print a))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;     (setq a (+ a 1))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, it will get more involved if we would like to support a clause without an initializer, or with no explicit step, but in general, manipulating your language with your language is more concise.
Again, I know why the book teaches it this way, and it is good to show that the &lt;code&gt;for&lt;/code&gt; loop can be implemented in terms of a &lt;code&gt;while&lt;/code&gt; loop, but here&amp;rsquo;s a second question - what the &lt;code&gt;for&lt;/code&gt; loop is for in Lox?&lt;/p&gt;
&lt;p&gt;There are no arrays in Lox, and you can&amp;rsquo;t index strings either.
The language will add objects later to teach how to implement object-oriented programming, but that&amp;rsquo;s a hard sell for me and doesn&amp;rsquo;t make &lt;code&gt;for&lt;/code&gt; more useful.
Because &lt;code&gt;for&lt;/code&gt; doesn&amp;rsquo;t support object traversal either.
Well, theoretically, we can implement the linked list using objects in Lox, and then traverse them using the &lt;code&gt;for&lt;/code&gt; loop like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; pair = ll.rest(); pair.tail != nil; pair = ll.rest()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; val = pair.head;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// do stuff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But that&amp;rsquo;s not a great interface for linked lists either.&lt;/p&gt;
&lt;p&gt;OK, I am nitpicking here.
But wait, there&amp;rsquo;s one more thing - where&amp;rsquo;s a &lt;code&gt;break&lt;/code&gt; statement?
Oh, there&amp;rsquo;s another &amp;ldquo;Challenge&amp;rdquo;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;In jlox, we had a challenge to add support for break statements.
This time, let’s do continue:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   continueStmt   &lt;span style=&#34;&#34;&gt;→&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;continue&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;&amp;#34;&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A continue statement jumps directly to the top of the nearest enclosing loop, skipping the rest of the loop body.
Inside a for loop, a continue jumps to the increment clause, if there is one.
It’s a compile-time error to have a continue statement not enclosed in a loop.&lt;/p&gt;
&lt;p&gt;Make sure to think about scope.
What should happen to local variables declared inside the body of the loop or in blocks nested inside the loop when a continue is executed?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wait, it&amp;rsquo;s not about implementing &lt;code&gt;break&lt;/code&gt;?
It&amp;rsquo;s about implementing &lt;code&gt;continue&lt;/code&gt;?!
Then, what happened to &lt;code&gt;break&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;break&lt;/code&gt; is completely omitted from &lt;code&gt;clox&lt;/code&gt;.
Well, it was a challenge in &lt;code&gt;jlox&lt;/code&gt;, and even back then I considered it to be a weird choice.
Loops without the &lt;code&gt;break&lt;/code&gt; statement are even more useless.
Again, you can overcome this by modifying the condition, but that&amp;rsquo;s extremely ugly.
The book has this example in the &amp;ldquo;Design Note&amp;rdquo; section:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; found = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; x = 0; x &amp;lt; xSize; x++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; y = 0; y &amp;lt; ySize; y++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; z = 0; z &amp;lt; zSize; z++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (matrix[x][y][z] == 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;found&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        found = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (found) &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (found) &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;They suggest that this can be rewritten using &lt;code&gt;goto&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; x = 0; x &amp;lt; xSize; x++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; y = 0; y &amp;lt; ySize; y++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; z = 0; z &amp;lt; zSize; z++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (matrix[x][y][z] == 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;found&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;goto&lt;/span&gt; done;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;done:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, this can be done like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; found = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; x = 0; !found &amp;amp;&amp;amp; x &amp;lt; xSize; x++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; y = 0; !found &amp;amp;&amp;amp; y &amp;lt; ySize; y++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; z = 0; !found &amp;amp;&amp;amp; z &amp;lt; zSize; z++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (matrix[x][y][z] == 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;found&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        found = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each &lt;code&gt;for&lt;/code&gt; loop will stop once &lt;code&gt;found&lt;/code&gt; is set to true.
While works, this is clumsy when you need to do an &lt;em&gt;early&lt;/em&gt; &lt;code&gt;break&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; x = 0; !done &amp;amp;&amp;amp; x &amp;lt; 10; x++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (x == 7) &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// rest of the body sits here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; done = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; x = 0; !done &amp;amp;&amp;amp; x &amp;lt; 10; x++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (x == 7) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    done = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// rest of the body has to be in the else clause
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While works, this isn&amp;rsquo;t particularly great.
I work with a language that has neither &lt;code&gt;break&lt;/code&gt; nor &lt;code&gt;continue&lt;/code&gt; - Fennel.
It doesn&amp;rsquo;t have an early &lt;code&gt;return&lt;/code&gt; either.
It works, however, because Fennel is a lisp-like language, even though it just compiles to Lua.
Its syntax is concise, and that allows us to write things with less indentation and nesting than in most other languages.
Still, sometimes it is clumsy to write a certain algorithm without an early &lt;code&gt;break&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;continue-and-break&#34;&gt;&lt;code&gt;continue&lt;/code&gt; and &lt;code&gt;break&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m not going to implement &lt;code&gt;continue&lt;/code&gt;, I just don&amp;rsquo;t feel like it, and certainly haven&amp;rsquo;t seen &lt;code&gt;continue&lt;/code&gt; used in any of the code in ten years.
But let&amp;rsquo;s just think how we could do that.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; i = 0; i &amp;lt; 10; i = i + 1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (i == 5) &lt;span style=&#34;font-weight:bold&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you may remember, this loop really compiles to this equivalent &lt;code&gt;while&lt;/code&gt; loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; i = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (i &amp;lt; 10) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (i == 5) &lt;span style=&#34;font-weight:bold&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    i = i + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, not quite - I lied to you.
In the bytecode this loops looks nothing like that, instead it is structured kinda like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; i = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  condition:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (i &amp;lt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;goto&lt;/span&gt; body:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  increment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  i = i + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;goto&lt;/span&gt; condition:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  body:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (i == 5) &lt;span style=&#34;font-weight:bold&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;goto&lt;/span&gt; increment:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Upon initialization, we create a &lt;code&gt;condition:&lt;/code&gt; label, followed by the &lt;code&gt;if&lt;/code&gt; statement.
If the &lt;code&gt;if&lt;/code&gt; clause is &lt;code&gt;true&lt;/code&gt; we &lt;code&gt;goto&lt;/code&gt; (or rather use the &lt;code&gt;JUMP&lt;/code&gt; instruction) to the &lt;code&gt;body:&lt;/code&gt; label.
Then, at the end of the body, we &lt;code&gt;goto&lt;/code&gt; to the &lt;code&gt;increment:&lt;/code&gt; label, which finally brings us back to the &lt;code&gt;condition:&lt;/code&gt; label.&lt;/p&gt;
&lt;p&gt;Convoluted, huh?
Well, the VM doesn&amp;rsquo;t really have a &lt;code&gt;goto&lt;/code&gt;, instead it uses the jumping instructions, but the idea is the same.
Now we need to somehow incorporate &lt;code&gt;continue&lt;/code&gt; in that.&lt;/p&gt;
&lt;p&gt;Semantically, &lt;code&gt;continue&lt;/code&gt; should just go to the &lt;code&gt;increment:&lt;/code&gt; label, right?
Well, yes, however, consider this loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; i = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (i &amp;lt; 10) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (i == 5) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; random = random_int(10);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// assume we can concatenate strings with numbers using +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;      print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;The loop will continue from&amp;#34;&lt;/span&gt; + random;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      i = random - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    i = i + 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, this is no different, we still can jump to the &lt;code&gt;increment:&lt;/code&gt; label, but what happens to the &lt;code&gt;random&lt;/code&gt; variable?
Correct, it leaks because by jumping we don&amp;rsquo;t properly close the scope.
So, we need to track how much scopes we jump over as well.&lt;/p&gt;
&lt;p&gt;And, mind that, &lt;code&gt;continue&lt;/code&gt; may not be the last expression in the scope, so we can&amp;rsquo;t simply close the scope on it.
It can be nested in multiple scopes too.&lt;/p&gt;
&lt;p&gt;Implementing &lt;code&gt;break&lt;/code&gt; is even harder, because it has to jump over the loop, but we can&amp;rsquo;t know the loop size, because our compiler is single-pass.
Storing the marker and patching it later made harder because &lt;code&gt;break&lt;/code&gt; is part of the expression inside the &lt;code&gt;loop&lt;/code&gt;, and so we need to have a stack of &lt;code&gt;break&lt;/code&gt; labels somewhere.&lt;/p&gt;
&lt;p&gt;On the first run I tried some approaches, but failed.
None of my solutions worked, and I honestly don&amp;rsquo;t know why.
I consider this partly a book&amp;rsquo;s failure - implementing &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt; is non-trivial, and just throwing it as a &amp;ldquo;Challenge&amp;rdquo; is cheap.
I&amp;rsquo;ve searched for different implementations of the Lox on the web, and I can&amp;rsquo;t remember if I found any with the &lt;code&gt;continue&lt;/code&gt; statement implemented.
Maybe, that&amp;rsquo;s because &lt;code&gt;continue&lt;/code&gt; is pretty much useless.
Maybe, because it&amp;rsquo;s hard and unclear how to do so.&lt;/p&gt;
&lt;p&gt;I would appreciate if the book had two versions of CLox implemented - one is a bare minimum by-the-book, the other one with all challenges completed.
I wonder, if this would change the contents of the book, because when I did the challenges, a lot of later material became less clear, because the code differed a lot by that time.
Anyhow, there&amp;rsquo;s the third &amp;ldquo;Challenge&amp;rdquo; wich would be interesting to see implemented &lt;em&gt;officially&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;Control flow constructs have been mostly unchanged since Algol 68.
Language evolution since then has focused on making code more declarative and high level, so imperative control flow hasn’t gotten much attention.&lt;/p&gt;
&lt;p&gt;For fun, try to invent a useful novel control flow feature for Lox.
It can be a refinement of an existing form or something entirely new.
In practice, it’s hard to come up with something useful enough at this low expressiveness level to outweigh the cost of forcing a user to learn an unfamiliar notation and behavior, but it’s a good chance to practice your design skills.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;What&amp;rsquo;s the point of this &amp;ldquo;Challenge&amp;rdquo;?
I don&amp;rsquo;t know - maybe you would came up with something like &lt;a href=&#34;https://en.wikipedia.org/wiki/COMEFROM&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;COMEFROM&lt;/code&gt;&lt;/a&gt;, or maybe you&amp;rsquo;ll be able to create something that will change computing forever.
I don&amp;rsquo;t want to waste time on pretty much useless stuff though.
If it&amp;rsquo;s meant to be a joke, then OK, but I didn&amp;rsquo;t get it.&lt;/p&gt;
&lt;h2 id=&#34;calls-and-functions&#34;&gt;Calls and Functions&lt;/h2&gt;
&lt;p&gt;Finally, some real action.
Defining functions is pretty straightforward, and I don&amp;rsquo;t really have anything to say about this chapter&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EXCEPT&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We’re not totally done, though.
The new return statement gives us a new compile error to worry about.
Returns are useful for returning from functions but the top level of a Lox program is imperative code too.
You shouldn’t be able to return from there.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;What?!&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We’ve specified that it’s a compile error to have a return statement outside of any function, which we implement like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;returnStatement&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiler.c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;in returnStatement()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (current-&amp;gt;type == TYPE_SCRIPT) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    error(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can&amp;#39;t return from top-level code.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (match(TOKEN_SEMICOLON)) {
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is one of the reasons we added that FunctionType enum to the compiler.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why?
I mean, even the book kinda mentions that it can be useful:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Allowing return at the top level isn’t the worst idea in the world.
It would give you a natural way to terminate a script early.
You could maybe even use a returned number to indicate the process’s exit code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The author seems to be familiar with Lua, so I don&amp;rsquo;t really get why they discard top-level = return statements.
In my implementation, I left this check out.
Especially because it helps with making testing possible again.&lt;/p&gt;
&lt;p&gt;As for performance&amp;hellip;
Well, the book mentions that the current by-the-book implementation of CLox is faster than Python at computing the factorial of a number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; fun fib(n) { if (n &amp;lt; 2) return n; return fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; var start = clock(); print fib(35); print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.22746e+06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.35232
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve checked this Python implementation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Python 3.11.5 (main, Aug 28 2023, 00:00:00) [GCC 13.2.1 20230728 (Red Hat 13.2.1-1)] on linux
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type &amp;#34;help&amp;#34;, &amp;#34;copyright&amp;#34;, &amp;#34;credits&amp;#34; or &amp;#34;license&amp;#34; for more information.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; def fib(n):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      if (n &amp;lt; 2):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        return n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      return fib(n - 2) + fib(n - 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;... ... ... ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; import time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; start = time.time(); print(fib(35)); print(time.time() - start)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.7716176509857178
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is certainly slower than CLox, what about my implementation in Zig?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./target/zig/bin/lox-0.1.73
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; fun fib(n) { if (n &amp;lt; 2) return n; return fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; var start = clock(); print fib(35); print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;28.784000158309937
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Almost 30 seconds?!
I&amp;rsquo;m not even sure where the problem is, the speed difference is drastic.
And I&amp;rsquo;m unsure how to diagnose this too, perhaps there&amp;rsquo;s a way to profile Zig code?
Apparently, there&amp;rsquo;s &lt;a href=&#34;https://github.com/wolfpld/tracy&#34; target=&#34;_blank&#34;&gt;this project&lt;/a&gt;, and there are &lt;a href=&#34;https://github.com/nektro/zig-tracy&#34; target=&#34;_blank&#34;&gt;bindings available&lt;/a&gt;, but I couldn&amp;rsquo;t make it build.&lt;/p&gt;
&lt;p&gt;Wait&amp;hellip;
Zig does all these safety checks by default, right?
And the default optimization target is &amp;ldquo;Debug&amp;rdquo;.
Let&amp;rsquo;s try compiling with other optimization levels:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -rf ./target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zig build -Doptimize=ReleaseSafe -p ./target/zig --cache-dir ./target/zig/.cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./target/zig/bin/lox-0.1.73
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; fun fib(n) { if (n &amp;lt; 2) return n; return fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; var start = clock(); print fib(35); print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3.015000104904175
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OK, &lt;code&gt;ReleaseSafe&lt;/code&gt; is ten times faster!
Let&amp;rsquo;s try &lt;code&gt;ReleaseFast&lt;/code&gt; then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm -rf ./target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zig build -Doptimize=ReleaseFast -p ./target/zig --cache-dir ./target/zig/.cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./target/zig/bin/lox-0.1.73
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; fun fib(n) { if (n &amp;lt; 2) return n; return fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; var start = clock(); print fib(35); print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.7879998683929443
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we&amp;rsquo;re as fast as Python, yay&amp;hellip;
Let&amp;rsquo;s throw in Lua for comparison:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Lua 5.4.4  Copyright (C) 1994-2022 Lua.org, PUC-Rio
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; function fib(n) if (n &amp;lt; 2) then return n end return fib(n - 2) + fib(n - 1) end
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; socket = require&amp;#34;socket&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; time = socket.gettime
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; start = time(); print(fib(35)); print(time() - start)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.0116229057312
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, Lua is often called one of the fastest scripting languages, so I guess that statement holds up well.
A complete CLox implementation by the author of the book is also fast:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; fun fib(n) { if (n &amp;lt; 2) return n; return fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; var start = clock(); print fib(35); print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.22746e+06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.3271
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, the way the result is printed isn&amp;rsquo;t particularly helpful.&lt;/p&gt;
&lt;p&gt;Well, now, that is sorted out, I think we can conclude that the implementation is fast enough.
I will keep the debug optimization target for now, as all these checks are helpful, but I guess I need a separate &lt;code&gt;make&lt;/code&gt; rule for a release build.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s one &amp;ldquo;Challenge&amp;rdquo; in this chapter I&amp;rsquo;d like to tackle:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;Add some more native functions to do things you find useful.
Write some programs using those.
What did you add?
How do they affect the feel of the language and how practical it is?&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here are two functions that I would consider useful.&lt;/p&gt;
&lt;p&gt;The first one is &lt;code&gt;length&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; lengthNative(n: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, args: [*]Value, vm: *VM) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (n &amp;gt; 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; s = args[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (s.isString())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; .{ .OK = Value.from(s.asString().bytes.len) };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected a string as an argument.&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simply put, it&amp;rsquo;s handy to be able to know the length of the string.
It&amp;rsquo;s not generic, because there are no other countable data structures in Lox.&lt;/p&gt;
&lt;p&gt;As you may noticed, the return value of this function is not of a &lt;code&gt;Value&lt;/code&gt; type but an &lt;code&gt;Result&lt;/code&gt; one.
That&amp;rsquo;s because we have to signal a runtime error if we get something unexpected as an argument.
It plays nicely with the previous Challenge:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;Right now, there’s no way for a native function to signal a runtime error.
In a real implementation, this is something we’d need to support because native functions live in the statically typed world of C but are called from dynamically typed Lox land.
If a user, say, tries to pass a string to sqrt(), that native function needs to report a runtime error.&lt;/p&gt;
&lt;p&gt;Extend the native function system to support that.
How does this capability affect the performance of native calls?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;As for performance - we&amp;rsquo;re wrapping the result, and Zig is quite good at unwrapping these with the &lt;code&gt;switch&lt;/code&gt; statement.
Here&amp;rsquo;s how we handle native calls now:&lt;/p&gt;
&lt;p&gt;The other one is &lt;code&gt;tostring&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; tostringNative(nargs: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, args: [*]Value, vm: *VM) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (nargs == 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected an argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; array_list = std.ArrayList(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;).init(vm.allocator);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; array_list.deinit();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    args[0].format(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;, .{}, array_list.writer()) &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        common.exit(200, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t tostring a value&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; s = array_list.toOwnedSlice() &lt;span style=&#34;font-weight:bold&#34;&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        common.exit(200, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OOME: can&amp;#39;t tostring a value&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;defer&lt;/span&gt; vm.allocator.free(s);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; .{ .OK = (&lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; String.copy(vm, s)).obj.asValue() };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lox allows us to concatenate strings using the &lt;code&gt;+&lt;/code&gt; operator.
However, this is almost useless, because we can&amp;rsquo;t concatenate anything else to it.
Formatting a message is pretty much impossible.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;tostring&lt;/code&gt; we can use &lt;code&gt;+&lt;/code&gt; with anything Lox supports:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; fun countdown(n) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          for (var i = n; i &amp;gt; 0; i = i - 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            print tostring(i) + &amp;#34;...&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          print &amp;#34;liftoff!!&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; countdown(3);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;liftoff!!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I would also consider adding &lt;code&gt;sleep&lt;/code&gt; to the language, as this function is very useful when you need to wait, but don&amp;rsquo;t want to waste CPU.
However, Lox is more of a toy language, so having sleep in it isn&amp;rsquo;t necessary.
Anyway, here&amp;rsquo;s &lt;code&gt;sleep&lt;/code&gt; for completeness:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; sleepNative(nargs: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, args: [*]Value, vm: *VM) Result {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (nargs == 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected an argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; arg = args[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!arg.is(.Number))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected an integer argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; f = arg.asNumber();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; i: &lt;span style=&#34;font-weight:bold&#34;&gt;i64&lt;/span&gt; = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromFloat&lt;/span&gt;(f);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (f != &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@floatFromInt&lt;/span&gt;(i)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected an integer argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (i &amp;gt; 0) sleep(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(i * 1000000));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; .{.OK = Nil };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It doesn&amp;rsquo;t have much utility, though, but having both the &lt;code&gt;clock&lt;/code&gt; and &lt;code&gt;sleep&lt;/code&gt; functions can work wonders.&lt;/p&gt;
&lt;h2 id=&#34;closures&#34;&gt;Closures&lt;/h2&gt;
&lt;p&gt;This is getting out of hand - we&amp;rsquo;ve been adding new object types, and each one requires a method to test if it&amp;rsquo;s an instance of a particular object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Obj = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    objType: Type,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    next: ?*Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isString(self: *Obj) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.objType == .String;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asString(self: *Obj) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@fieldParentPtr&lt;/span&gt;(String, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;, self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isFunction(self: *Obj) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.objType == .Function;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asFunction(self: *Obj) *Function {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@fieldParentPtr&lt;/span&gt;(Function, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;, self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isNativeFunction(self: *Obj) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.objType == .NativeFunction;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asNativeFunction(self: *Obj) *NativeFunction {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@fieldParentPtr&lt;/span&gt;(NativeFunction, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;, self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we need to add one more for &lt;code&gt;Closure&lt;/code&gt;, and then a bunch of others too.
You can see that the only difference between these methods is the enumeration tag or type.
So, instead of adding new ones, let&amp;rsquo;s delete all of these and use Zig&amp;rsquo;s &lt;code&gt;comptime&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Obj = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    objType: Type,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    next: ?*Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; is(self: *Obj, objType: Type) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.objType == objType;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; as(self: *Obj, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;) *T {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@fieldParentPtr&lt;/span&gt;(T, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;, self);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we only need to update all of our code from &lt;code&gt;x.isFunction()&lt;/code&gt; to &lt;code&gt;x.is(Function)&lt;/code&gt; which is a simple enough substitution.
Sadly, we can&amp;rsquo;t do the same for our evergrowing &lt;code&gt;Value&lt;/code&gt; struct:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Obj: *Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isNumber(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Number;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isBool(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Bool;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isObj(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may seem that we can do the same, except use the enumeration literal as the parameter to &lt;code&gt;is&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; is(self: Value, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; target: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(.enum_literal)) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, we also have methods like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isString(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == .String;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, here we can&amp;rsquo;t use this kind of signature.
We could do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; is(self: Value, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; target: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(.enum_literal), objType: ObjType) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; target == .Obj) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == target &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == objType;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But then it would require us to write &lt;code&gt;x.is(.Number, undefined)&lt;/code&gt; and &lt;code&gt;y.is(.Obj, .String)&lt;/code&gt;, which is ugly.
So instead, we can do this &lt;code&gt;comptime&lt;/code&gt; check:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; is(self: Value, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; target: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(.enum_literal)) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@hasField&lt;/span&gt;(ObjType, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@tagName&lt;/span&gt;(target))) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way we can write both &lt;code&gt;x.is(.Number)&lt;/code&gt; and &lt;code&gt;y.is(.String)&lt;/code&gt; and it will generate an appropriate code at compile time.
This is as close as we can get to macros, I guess.
It gets harder from there, though.&lt;/p&gt;
&lt;p&gt;Now we need to get rid of these methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Obj: *Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asNumber(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Number;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asBool(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Bool;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asObj(self: Value) *Obj {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asString(self: Value) *String {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj.as(String);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asFunction(self: Value) *Function {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj.as(Function);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asNativeFunction(self: Value) *NativeFunction {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj.as(NativeFunction);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, we again have two kinds of actions to perform - one is to return the desired enumeration tag value, and the other is to call a method.
The first few are easy to convert by using the same trick with &lt;code&gt;comptime target: @TypeOf(.enum_literal)&lt;/code&gt; but we can&amp;rsquo;t do the same for the last few, because &lt;code&gt;Obj.as&lt;/code&gt; expects a &lt;code&gt;type&lt;/code&gt;.
On the other hand, we know all of the types we&amp;rsquo;re gonna use with &lt;code&gt;as&lt;/code&gt;, so we can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Obj: *Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; typeNameUnqualified(&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;) []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; name = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(T);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; name[&lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (std.mem.lastIndexOfAny(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, name, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;)) |i| i + 1 &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; 0..];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; as(self: Value, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;) T {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@hasField&lt;/span&gt;(ObjType, typeNameUnqualified(T)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self.Obj.as(&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeInfo&lt;/span&gt;(T)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Pointer =&amp;gt; |p| p.child,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; T,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (T) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt; =&amp;gt; self.Number,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; =&amp;gt; self.Bool,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; =&amp;gt; self.Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            *Obj =&amp;gt; self.Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not pretty, eh?
Well, that&amp;rsquo;s what you get, when you don&amp;rsquo;t have macros that operate on actual code.&lt;/p&gt;
&lt;p&gt;We call this function for basic types like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a.as(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Value{.Number=42} =&amp;gt; 42
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Transforming the &lt;code&gt;Value&lt;/code&gt; into an actual number.
And for object types, we do it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// s is a `Value{.Obj=&amp;amp;{objType=.String,next=null}}`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;s.as(*String); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// =&amp;gt; &amp;amp;String{.Obj={objType=.String,next=null},.hash=1337,.bytes=&amp;#34;ваыв&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because we want a pointer to the &lt;code&gt;String&lt;/code&gt; type we pass it as &lt;code&gt;*String&lt;/code&gt;.
Seems logical, but there&amp;rsquo;s a problem.&lt;/p&gt;
&lt;p&gt;First, we need to check if the &lt;code&gt;ObjType&lt;/code&gt; enum has the &lt;code&gt;String&lt;/code&gt; &lt;strong&gt;field&lt;/strong&gt;, but here we have a type.
More than that, it is actually an &lt;code&gt;*src.object.String&lt;/code&gt; type, not just &lt;code&gt;String&lt;/code&gt;, so we need a way to transform this type into a tag name.
The &lt;code&gt;typeNameUnqualified&lt;/code&gt; function takes care of it, but then there&amp;rsquo;s another problem - we need to pass the correct type to the &lt;code&gt;Object.as&lt;/code&gt; method, and &lt;code&gt;*String&lt;/code&gt; is not a correct type - it needs a &lt;code&gt;String&lt;/code&gt;!
So we have to do a little dance with &lt;code&gt;@typeInfo&lt;/code&gt; and check that we got a &lt;code&gt;Pointer&lt;/code&gt; type, that has a &lt;code&gt;child&lt;/code&gt; field, containing the type we&amp;rsquo;re interested in.
Then we can pass it to the &lt;code&gt;as&lt;/code&gt; method of the object.&lt;/p&gt;
&lt;p&gt;Phew!
We&amp;rsquo;re almost done with the refactoring, the only thing left is to remove these methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Obj: *Obj,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ..
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; fromNumber(x: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;) Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Value{ .Number = x };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; fromBool(x: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;) Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Value{ .Bool = x };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; fromObj(x: *Obj) Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Value{ .Obj = x };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, that&amp;rsquo;s easy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; from(x: anytype) Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(x)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime_float&lt;/span&gt; =&amp;gt; Value{ .Number = x },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; =&amp;gt; Value{ .Bool = x },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; =&amp;gt; Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        *Obj =&amp;gt; Value{ .Obj = x },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can do &lt;code&gt;Value.from(12.3)&lt;/code&gt; and it will do it&amp;rsquo;s job smoothly.&lt;/p&gt;
&lt;p&gt;Look at the before and after:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------------------------Before------------------------------------+----------------------------------------After----------------------------------------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {                                        | &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt;) {                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,                                                       |     Number: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;,                                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,                                                        |     Bool: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;,                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    Nil,                                                               |     Nil,                                                                            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    Obj: *Obj,                                                         |     Obj: *Obj,                                                                      |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...                                                             |     // ...                                                                          |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isNumber(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                         |     &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; is(self: Value, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; target: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(.enum_literal)) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Number;                                        |         &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@hasField&lt;/span&gt;(ObjType, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@tagName&lt;/span&gt;(target))) {                        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |             &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == target;                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |         } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {                                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; fromNumber(x: &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;) Value {                           |             &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == target;                                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Value{ .Number = x };                                   |         }                                                                           |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |     }                                                                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asNumber(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt; {                          |     &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; typeNameUnqualified(&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;) []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt; {                           |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Number;                                            |         &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; name = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(T);                                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |         &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; name[&lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (std.mem.lastIndexOfAny(&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, name, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;)) |i| i + 1 &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; 0..]; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |     }                                                                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isBool(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                           |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Bool;                                          |     &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; as(self: Value, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;) T {                             |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |         &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@hasField&lt;/span&gt;(ObjType, typeNameUnqualified(T)))             |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |             self.Obj.as(&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeInfo&lt;/span&gt;(T)) {                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; fromBool(x: &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;) Value {                            |                 .Pointer =&amp;gt; |p| p.child,                                            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Value{ .Bool = x };                                     |                 &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; T,                                                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |             })                                                                      |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |         &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (T) {                                                           |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asBool(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                           |             &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt; =&amp;gt; self.Number,                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Bool;                                              |             &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; =&amp;gt; self.Bool,                                                      |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |             &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; =&amp;gt; self.Nil,                                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |             *Obj =&amp;gt; self.Obj,                                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isObj(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                            |             &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj;                                           |         };                                                                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |     }                                                                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; fromObj(x: *Obj) Value {                             |     &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; from(x: anytype) Value {                                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Value{ .Obj = x };                                      |         &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(x)) {                                                |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |             &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime_float&lt;/span&gt; =&amp;gt; Value{ .Number = x },                            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |             &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; =&amp;gt; Value{ .Bool = x },                                             |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asObj(self: Value) *Obj {                            |             &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; =&amp;gt; Nil,                                                            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj;                                               |             *Obj =&amp;gt; Value{ .Obj = x },                                              |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |             &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |         };                                                                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isString(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                         |     }                                                                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == .String;           | };                                                                                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asString(self: Value) *String {                      |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj.asString();                                    |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isFunction(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == .Function;         |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asFunction(self: Value) *Function {                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj.asFunction();                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isNativeFunction(self: Value) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {                 |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self == .Obj &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; self.Obj.objType == .NativeFunction;   |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                                                                       |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; asNativeFunction(self: Value) *NativeFunction {      |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.Obj.asNativeFunction();                            |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|    }                                                                  |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|};                                                                     |                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------------------------------------------------------------------+-------------------------------------------------------------------------------------|
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I guess, you can do many things that are done with macros in C using the comptime in Zig, although mostly when it is related to types.
Can&amp;rsquo;t say that I like this more than macros, but it gets the job done.
Now we can start this chapter proper!&lt;/p&gt;
&lt;p&gt;In the last chapter, we added functions and had them working, but you can do with just functions only so much.
In this chapter, we&amp;rsquo;re adding closures, which take our functions to a whole other level.&lt;/p&gt;
&lt;p&gt;Honestly, this chapter, while having mostly straightforward stuff, gave me a lot of trouble.
You see, there&amp;rsquo;s a certain problem with how the book gives you the material.
It&amp;rsquo;s subtle, but when the time comes it&amp;rsquo;s hard to ignore.&lt;/p&gt;
&lt;p&gt;The book gives you information bit by bit while trying to have a working interpreter at all times.
Yes, each chapter breaks the interpreter in the beginning, but by the end, you have something that works.
And often the chapter progressively gives you more examples and explains why they should work and why they don&amp;rsquo;t right now.
On its own, it&amp;rsquo;s a great way to show you your progress, but on the other hand, if a small mistake sneaks somewhere in the process, you won&amp;rsquo;t know till much later.
That&amp;rsquo;s exactly what happened to me.&lt;/p&gt;
&lt;p&gt;So, during this chapter, I tried most examples the book featured, and all of them seemed to work.
Satisfied, I proceeded to the &amp;ldquo;Challenges&amp;rdquo; section, and because I despise OOP much more than said &amp;ldquo;Challenges&amp;rdquo;, I decided to do this particular one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;a href=&#34;http://wiki.c2.com/?ClosuresAndObjectsAreEquivalent&#34; target=&#34;_blank&#34;&gt;famous koan&lt;/a&gt; teaches us that &amp;ldquo;objects are a poor man’s closure&amp;rdquo; (and vice versa).
Our VM doesn&amp;rsquo;t support objects yet, but now that we have closures we can approximate them.
Using closures, write a Lox program that models two-dimensional vector &amp;ldquo;objects&amp;rdquo;.
It should:
&lt;ul&gt;
&lt;li&gt;Define a &amp;ldquo;constructor&amp;rdquo; function to create a new vector with the given x and y coordinates.&lt;/li&gt;
&lt;li&gt;Provide &amp;ldquo;methods&amp;rdquo; to access the x and y coordinates of values returned from that constructor.&lt;/li&gt;
&lt;li&gt;Define an addition &amp;ldquo;method&amp;rdquo; that adds two vectors and produces a third.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;And it threw a weird error - it couldn&amp;rsquo;t find &lt;em&gt;some&lt;/em&gt; closures.&lt;/p&gt;
&lt;p&gt;Now, because Lox doesn&amp;rsquo;t have any data structures except for strings yet, I decided to implement a linked list, as closures are a perfect solution for that.
You don&amp;rsquo;t need any kind of data structures for linked lists as long as your language has closures.
Observe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun cons(head, tail) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fun cell(isHead) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (isHead)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; head;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; tail;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cell;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun first(cell) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cell(&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun rest(cell) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; cell(&lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these three functions, we should be able to create a list like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; list = cons(1, cons(2, cons(3, nil)));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we should be able to traverse it with &lt;code&gt;for&lt;/code&gt; loop, albeit in a bit ugly way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; head = list; head != nil; head = rest(head)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	print first(head);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we try to execute this script, we get&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ziglox list.lox
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Undefined variable &amp;#39;head&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[line 1] in cell
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[line 1] in first
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[line 1] in script
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Interpret Runtime Error
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An error.
I then made sure that the &lt;code&gt;head&lt;/code&gt; variable is not related to the loop, by trying to get the head of the list with just &lt;code&gt;first(list)&lt;/code&gt;, but still got the same error.
Then I spent a day looking for what I did wrong.&lt;/p&gt;
&lt;p&gt;During this, I decided to try out all of the examples in the chapter.
I remember that all of them have worked before, and if they are then the problem is much deeper than the book accounts for.
So I started, and everything worked until I hit this one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun outer() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; x = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fun middle() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fun inner() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      print x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;create inner closure&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; inner;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;return from outer&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; middle;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; mid = outer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; = mid();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Strangely enough, all later examples worked fine.
I&amp;rsquo;ll explain why in a moment.
For now, let it sink in - I had a working interpreter the whole time, and it could do everything the book suggested I try, yet there was a bug somewhere.&lt;/p&gt;
&lt;p&gt;So, here&amp;rsquo;s the thing.
For some reason, I decided to use a statically allocated stack for locals, back in the chapter where we added support for locals.
It worked well until we were introduced to the concept of compiler stacks.
However, Since I created the stack way back, I kept using it, and it basically meant that every compiler shared the same stack of locals.
So when we were searching for upvalues we saw the same upvalues on all levels.&lt;/p&gt;
&lt;p&gt;So you should now understand why it worked for all of the examples, except for the one above - it has one more compiler level.
After fixing this by using a proper dynamic array, all of the examples in this chapter work as expected.&lt;/p&gt;
&lt;p&gt;The linked list, however, still doesn&amp;rsquo;t work.
This time around, I decided that I would automate this process a bit, and put all of the examples as test cases.
I had to adjust them to actually return values instead of printing them, and what do you know - I found another broken case:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun outer() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; a = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; b = 2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fun middle() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; c = 3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; d = 4;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fun inner() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; a + c + b + d;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; inner;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; middle;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; outer()()();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It should return &lt;code&gt;10&lt;/code&gt;, but instead it returns &lt;code&gt;12&lt;/code&gt;.
How?
Well, if we print all of the values that went into the &lt;code&gt;inner&lt;/code&gt; function we&amp;rsquo;ll see that &lt;code&gt;a&lt;/code&gt; is &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; is &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt; is &lt;code&gt;2&lt;/code&gt;, and &lt;code&gt;d&lt;/code&gt; is &lt;code&gt;4&lt;/code&gt; and the answer changes to &lt;code&gt;14&lt;/code&gt;.
So while only the &lt;code&gt;d&lt;/code&gt; upvalue was correct, the introduction of &lt;code&gt;print&lt;/code&gt; still changed something.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another bug.
And the same happens in my linked list implementation - &lt;code&gt;first&lt;/code&gt; returns itself.
Perhaps something to do with how we capture upvalues then?&lt;/p&gt;
&lt;p&gt;During these days of debugging, I tried everything I could - I moved &lt;code&gt;readByte&lt;/code&gt; to &lt;code&gt;CallFrame&lt;/code&gt; struct, I changed the instruction counter to the instruction pointer, as the book does, I also tried allocating stacks on the heap instead of the static memory.
I poked the reference implementation by Robert - the bytecode is exactly the same as in my implementation, so it has to be something in the VM.
I printed pointer addresses, analyzing if there is a different between my implementation and C, and comparing relative offsets - again, they&amp;rsquo;re the same.
Nothing helped.
Reverting to my previous implementation revealed that this case wasn&amp;rsquo;t handled properly as well - I somehow missed it back then too.&lt;/p&gt;
&lt;p&gt;And then I found it.
After 4 days of debugging the reason was that I &lt;strong&gt;SOMEHOW&lt;/strong&gt; missed this line in the &lt;code&gt;captureUpvalue&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;createdUpvalue.next = upvalue;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, everything works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// cons, first, rest...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; list = cons(1, cons(2, cons(3, nil)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; head = list; head != nil; head = rest(head)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print first(head);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, guess what?
During all this debugging, and trying different things I managed to improve the speed of the interpreter a bit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; fun fib(n) { &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (n &amp;lt; 2) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; n; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; s = clock(); print fib(35); print clock() - s;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.4010000228881836
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s the same code when checked out to the previous commit at chapter 24:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; fun fib(n) { &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (n &amp;lt; 2) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; n; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; fib(n - 2) + fib(n - 1); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; s = clock(); print fib(35); print clock() - s;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9227465
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.815000057220459
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nice!
Going back to the third &amp;ldquo;Challenge&amp;rdquo;, here&amp;rsquo;s my attempt at an object via closures:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fun vec2(x, y) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; _x = x; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// storage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; _y = y;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fun obtainer(what) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (what == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; _x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (what == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;y&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; _y;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fun establisher(what, val) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (what == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;) _x = val;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (what == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;y&amp;#34;&lt;/span&gt;) _y = val;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fun add(other) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; ox = other(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obtain&amp;#34;&lt;/span&gt;)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; oy = other(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obtain&amp;#34;&lt;/span&gt;)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;y&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _x = _x + ox;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _y = _y + oy;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fun clss (action) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (action == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obtain&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; obtainer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (action == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;establish&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; establisher;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (action == &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;add&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; add;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; clss;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; a = vec2(3, nil);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; b = vec2(22, 10);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;establish&amp;#34;&lt;/span&gt;)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;y&amp;#34;&lt;/span&gt;, 7);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;add&amp;#34;&lt;/span&gt;)(b);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print a(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obtain&amp;#34;&lt;/span&gt;)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;) + a(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;obtain&amp;#34;&lt;/span&gt;)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;y&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// 42
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a &lt;code&gt;vec2&lt;/code&gt; structure representing this kind of data &lt;code&gt;{.x = 1, .y = 2}&lt;/code&gt;.
Although it&amp;rsquo;s a bit rough to use, it is a proper data structure.
And yes - I like &lt;code&gt;obtain&lt;/code&gt; and &lt;code&gt;establish&lt;/code&gt; better than &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt;.
What?&lt;/p&gt;
&lt;h2 id=&#34;garbage-collection&#34;&gt;Garbage Collection&lt;/h2&gt;
&lt;p&gt;Hooo&amp;hellip;&lt;/p&gt;
&lt;p&gt;Now we get to the interesting stuff.
The book implements this language in C, and C is pretty straightforward when it comes to memory management.
Well, straightforward might not be a proper word, but by default it&amp;rsquo;s quite basic - you have &lt;code&gt;malloc&lt;/code&gt;, &lt;code&gt;free&lt;/code&gt;, and &lt;code&gt;realloc&lt;/code&gt; as a base.&lt;/p&gt;
&lt;p&gt;Zig, on the other hand, doesn&amp;rsquo;t have a default allocator, which, in theory, should make it more appropriate for embedded systems, where there may not be any way to actually allocate memory.
This, in turn, affects the language design - every Zig function that wants to allocate some memory, accepts an allocator (or accesses it from an enclosing &lt;code&gt;struct&lt;/code&gt; if that&amp;rsquo;s a method).
Now you can understand why all of the code in this post had something like &lt;code&gt;Allocator&lt;/code&gt; in function arguments or structures.&lt;/p&gt;
&lt;p&gt;This meant that we didn&amp;rsquo;t have to implement most of the book&amp;rsquo;s &lt;code&gt;memory.c&lt;/code&gt; and &lt;code&gt;memory.h&lt;/code&gt; because Zig&amp;rsquo;s allocators already can do all of that.
However, now we can&amp;rsquo;t just use an existing allocator, as we need to implement garbage collection mid-allocation.
That&amp;rsquo;s why we need a custom allocator.&lt;/p&gt;
&lt;p&gt;Thankfully, we don&amp;rsquo;t really have to do the allocation ourselves.
Instead, we can create an allocator that just wraps another allocator, like a decorator.
All we need to do is to implement these three functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; GCAllocator = &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    parentAllocator: Allocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bytesAllocated: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; init(parentAllocator: Allocator) GCAllocator {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; .{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .parentAllocator = parentAllocator,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .bytesAllocated = 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; allocator(self: *GCAllocator) Allocator {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; .{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .ptr = self,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .vtable = &amp;amp;.{ .alloc = alloc, .resize = resize, .free = free },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; alloc(ctx: *anyopaque, len: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, log2_ptr_align: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, ra: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;) ?[*]&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; self: *GCAllocator = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrCast&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@alignCast&lt;/span&gt;(ctx));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; result = self.parentAllocator.rawAlloc(len, log2_ptr_align, ra);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (result != &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;) self.bytesAllocated += len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; result;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; resize(ctx: *anyopaque, buf: []&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, log2_buf_align: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, new_len: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, ra: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; self: *GCAllocator = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrCast&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@alignCast&lt;/span&gt;(ctx));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.parentAllocator.rawResize(buf, log2_buf_align, new_len, ra)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (new_len &amp;lt;= buf.len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                self.bytesAllocated -= buf.len - new_len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                self.bytesAllocated += new_len - buf.len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        std.debug.assert(new_len &amp;gt; buf.len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; free(ctx: *anyopaque, buf: []&lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, log2_buf_align: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, ra: &lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; self: *GCAllocator = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrCast&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@alignCast&lt;/span&gt;(ctx));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.parentAllocator.rawFree(buf, log2_buf_align, ra);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self.bytesAllocated -= buf.len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we should be able to implement the rest of this chapter in terms of this allocator.
And, thanks to the fact that all our functions already accept an allocator, we can just plug this one in, and it should work!&lt;/p&gt;
&lt;p&gt;I called it &lt;code&gt;GCAllocator&lt;/code&gt;, although right now it is more like a &lt;em&gt;tracking&lt;/em&gt; allocator.
It tracks how many bytes were allocated and freed, and that&amp;rsquo;s basically it.
With that, we can implement the rest of the interface.&lt;/p&gt;
&lt;p&gt;The book suggests to implement the &amp;ldquo;Mark and Sweep&amp;rdquo; algorithm.
While not great, it is perfect for teaching.
Moreover, there&amp;rsquo;s still software that uses this technique, for example, one that I&amp;rsquo;m writing this blog in - Emacs!
It was always an active debate whether the GC in Emacs is outdated or not, but I can say that Emacs performs fine for my daily tasks, so it&amp;rsquo;s probably OK.
Something like JVM would never settle on something simple like this though.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t go into the source code of the collector itself, as the translation from C is pretty much 1:1 here.
One thing to point out though is the use of &lt;code&gt;grayStack&lt;/code&gt; in the VM.
The book uses an array of pointers to the objects, and we do the same by using &lt;code&gt;ArrayList(*Obj)&lt;/code&gt;.
However, using &lt;code&gt;append&lt;/code&gt; to add things to this array can throw an out-of-memory error.
So when we do the marking of objects we have to handle that.&lt;/p&gt;
&lt;p&gt;Between these two chapters, I&amp;rsquo;ve refactored the code to use Zig&amp;rsquo;s errors.
So handling allocation failures is simple enough now, but I don&amp;rsquo;t really know if we &lt;em&gt;should&lt;/em&gt; handle out-of-memory errors.
On one hand, JVM doesn&amp;rsquo;t recommend handling the OOME, and the most common practice I know of is to do a heap dump and die.
On the other hand, we&amp;rsquo;re dealing with OOME inside the virtual machine, not inside the language itself, as Lox doesn&amp;rsquo;t really have exceptions or other kinds of error handling.
I chose to kill the VM if the OOME ever occurs, but in a real language, I would probably not do it this way.
And I think in the language that runs on the VM it should be possible to handle OOM too.&lt;/p&gt;
&lt;h2 id=&#34;classes-and-instances&#34;&gt;Classes and Instances&lt;/h2&gt;
&lt;p&gt;Now, I&amp;rsquo;m a bit torn apart here.
I don&amp;rsquo;t want to implement classes.&lt;/p&gt;
&lt;p&gt;I mean, seriously, this language doesn&amp;rsquo;t have any data structures yet, and we&amp;rsquo;re already in classes?
Where are arrays, at the very least?
Plus, we already did classes in &lt;code&gt;cljlox&lt;/code&gt;, so it&amp;rsquo;s boring to do it again.&lt;/p&gt;
&lt;p&gt;Instead, I think it would be better to go the Lua route and give users only a basic set of data structures, like hash tables.
Except, actually give users data structure&lt;b&gt;s&lt;/b&gt;, and not a mixed table/array thingy.
I&amp;rsquo;m not sure, however, if it will affect the last chapter that talks about optimizations.&lt;/p&gt;
&lt;p&gt;Yet, there are benefits in the following chapters.
For example, if I were to introduce a hash table, accessing keys from it can be made with a special syntax like &lt;code&gt;a.b&lt;/code&gt;.
Assigning a value to the key can also use this syntax, and we&amp;rsquo;re going to handle it in the next chapter.&lt;/p&gt;
&lt;p&gt;I guess, classes are more involved, and thus a bit better fit for teaching how to make a language, but on the other hand, class systems can be a fully runtime thing.
Sparkle some macros on top of it, and you can hack your own object system in a weekend.
That&amp;rsquo;s what a lot of Lisp/Scheme projects did back in the day.&lt;/p&gt;
&lt;p&gt;Anyway, after adding the &lt;code&gt;Class&lt;/code&gt; opcode and some other stuff around it the book says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There you have it, our VM supports classes now. You can run this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; Brioche {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print Brioche;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, printing is about all you can do with classes, so next is making them more useful.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unfortunately, we have classes before arrays.&lt;/p&gt;
&lt;p&gt;Yes, I&amp;rsquo;m negative, because come on, arrays are such a basic data structure that not having them is a bummer.
How would you implement anything without an array?
Well, technically, we can use our closure-based linked lists as a substitute, but it has horrible performance in many algorithms where constant indexing is required.&lt;/p&gt;
&lt;p&gt;Anyway, after implementing field access the chapter is suddenly over.
That&amp;rsquo;s it?
Well, right now it&amp;rsquo;s just a hash table with inconvenient syntax.
I mean, yes, classes are just a special case of a hash table in some languages, and hash tables are a special case of classes in some other &lt;em&gt;broken&lt;/em&gt; languages.
But here, why didn&amp;rsquo;t we introduce a basic hash table with an open set of keys, even though our runtime already supports one?&lt;/p&gt;
&lt;p&gt;Onto &amp;ldquo;Challenges&amp;rdquo;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Trying to access a non-existent field on an object immediately aborts the entire VM.
The user has no way to recover from this runtime error, nor is there any way to see if a field exists before trying to access it.
It’s up to the user to ensure on their own that only valid fields are read.&lt;/p&gt;
&lt;p&gt;How do other dynamically typed languages handle missing fields?
What do you think Lox should do?
Implement your solution.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, that was a strange decision.
I decided to just return &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Fields are accessed at runtime by their string name.
But that name must always appear directly in the source code as an identifier token.
A user program cannot imperatively build a string value and then use that as the name of a field.
Do you think they should be able to?
Devise a language feature that enables that and implement it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, first of all, a user program cannot imperatively build a string value at all, because Lox has no string library.
A few chapters ago I added &lt;code&gt;tostring&lt;/code&gt; and with that, it is possible to build strings using &lt;code&gt;+&lt;/code&gt;, but not in vanilla Lox.&lt;/p&gt;
&lt;p&gt;A user should be able to do that, but most languages that allow that it does require a special syntax, and I don&amp;rsquo;t want to deal with that now.
If I did, though, I would probably introduce something like &lt;code&gt;foo[bar]&lt;/code&gt;, but instead we can always use a native function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; getNative(nargs: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, args: [*]Value, vm: *VM) !Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (nargs == 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected an argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; instance = args[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!instance.is(.Instance))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected a class instance as the first argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; name = args[1];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!name.is(.String))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected a string as the second argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; instance.as(*Instance).fields.get(name.as(*String)) &lt;span style=&#34;font-weight:bold&#34;&gt;orelse&lt;/span&gt; Nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; setNative(nargs: &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;, args: [*]Value, vm: *VM) !Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (nargs == 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected an argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; instance = args[0];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!instance.is(.Instance))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected a class instance as the first argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; name = args[1];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (!name.is(.String))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; vm.runtimeError(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected a string as the second argument&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (nargs &amp;gt;= 3 &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; !args[2].is(.Nil)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; value = args[2];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _ = &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; instance.as(*Instance).fields.set(name.as(*String), value);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _ = instance.as(*Instance).fields.delete(name.as(*String));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; Nil;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these we can do &lt;code&gt;set(foo, &amp;quot;vaiv&amp;quot;, 42)&lt;/code&gt; and &lt;code&gt;get(foo, &amp;quot;vaiv&amp;quot;)&lt;/code&gt;.
These native functions are bloating the &lt;code&gt;VM&lt;/code&gt; struct, so I should probably move them out.&lt;/p&gt;
&lt;p&gt;As you can see, I don&amp;rsquo;t care if the native function has more arguments than it really needs.
The only thing I care about is the required arguments.
I like this design more, and in fact, doing things this way should allow variadic functions naturally.
Maybe I should implement them in the future, alongside arrays.&lt;/p&gt;
&lt;p&gt;Lastly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Conversely, Lox offers no way to remove a field from an instance.
You can set a field’s value to nil, but the entry in the hash table is still there.
How do other languages handle this?
Choose and implement a strategy for Lox.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;But as you may have noticed, I already implemented this.
Setting a field to &lt;code&gt;nil&lt;/code&gt; removes it from the hash table.
This is how it works in Lua, and while I strongly dislike this particular part of Lua, I don&amp;rsquo;t have any problems with this in Lox.
Why?
Because Lua has a weird mix of tables and arrays, setting a value in the array to &lt;code&gt;nil&lt;/code&gt; also removes it from the array, as if the array were a hash table with integer keys.&lt;/p&gt;
&lt;p&gt;So by doing &lt;code&gt;arr[3] = nil&lt;/code&gt; you effectively transform &lt;code&gt;{&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;, &amp;quot;d&amp;quot;}&lt;/code&gt; into &lt;code&gt;{1 = &amp;quot;a&amp;quot;, 2 = &amp;quot;b&amp;quot;, 4 = &amp;quot;d&amp;quot;}&lt;/code&gt;, or rather &lt;code&gt;{&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, 4 = &amp;quot;d&amp;quot;}&lt;/code&gt;, as Lua views it.
This breaks iteration on arrays, as no the iteration will only see the first two fields (and yes, arrays in Lua start from &lt;code&gt;1&lt;/code&gt;, which is great):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;arr = {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-- before set --&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; ipairs(arr) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   print(i, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;arr[3] = &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-- after set --&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; ipairs(arr) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   print(i, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-- before set --
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1	a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2	b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3	c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4	d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-- after set --
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1	a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2	b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If Lua did not remove things when you set them to &lt;code&gt;nil&lt;/code&gt; and instead provided a &lt;code&gt;contains&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; functions to check for key presence, and removal of combined array/table would be fine, but in its current state, it&amp;rsquo;s too easy to trip on this.
I know that because I teach people how to write Lua, and this always makes people angry.&lt;/p&gt;
&lt;p&gt;If the language provides separate array and table objects, setting table keys to &lt;code&gt;nil&lt;/code&gt; for removal is fine - it should not matter if the key is present and &lt;code&gt;nil&lt;/code&gt; or just absent.
Arrays, however, should be able to have &lt;code&gt;nil&lt;/code&gt; in them, and removal is a whole different operation, that shifts all other elements, so setting array elements to &lt;code&gt;nil&lt;/code&gt; for removal doesn&amp;rsquo;t really make sense.
Anyway, that&amp;rsquo;s my reasoning behind this, I&amp;rsquo;m sure you can disagree, but it&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;Finally:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;
&lt;p&gt;Because fields are accessed by name at runtime, working with instance state is slow.
It’s technically a constant-time operation—thanks, hash tables—but the constant factors are relatively large.
This is a major component of why dynamic languages are slower than statically typed ones.&lt;/p&gt;
&lt;p&gt;How do sophisticated implementations of dynamically typed languages cope with and optimize this?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ah, if only we had arrays - we could easily implement records that have constant time access to fields by field index determined at compile time.
Alas.&lt;/p&gt;
&lt;h2 id=&#34;methods-and-initializers&#34;&gt;Methods and Initializers&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t have anything to say about this chapter.
Mostly, because it is straightforward and concise.&lt;/p&gt;
&lt;p&gt;Still, I would prefer not having methods at all, but there were interesting bits to tackle with &lt;code&gt;this&lt;/code&gt;, so I guess it was worth it.&lt;/p&gt;
&lt;h2 id=&#34;superclasses&#34;&gt;Superclasses&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...return constantInstruction(&amp;#34;OP_CLASS&amp;#34;, chunk, offset);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; OP_INHERIT:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; simpleInstruction(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;OP_INHERIT&amp;#34;&lt;/span&gt;, offset);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;//  case OP_METHOD: ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Simple instruction&lt;/em&gt;, how ironic.&lt;/p&gt;
&lt;p&gt;The chapter proceeds adding tons of new stuff in the compiler, and then in the VM.
While straightforward, I can&amp;rsquo;t help but notice how things got more complicated since we added classes.
Honestly, I have never seen a program where inheritance made things easier.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A tenet of object-oriented programming is that a class should ensure new objects are in a valid state.
In Lox, that means defining an initializer that populates the instance’s fields.
Inheritance complicates invariants because &amp;hellip;&lt;/p&gt;
&lt;p&gt;If Lox was your language, how would you address this, if at all?
If you would change the language, implement your change.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;If Lox was my language it wouldn&amp;rsquo;t have classes at all.
And it would have arrays.&lt;/p&gt;
&lt;h2 id=&#34;optimization&#34;&gt;Optimization&lt;/h2&gt;
&lt;p&gt;The final chapter.
Honestly, didn&amp;rsquo;t think that I&amp;rsquo;d make it through.
It&amp;rsquo;s 4 AM right now, as I&amp;rsquo;m writing this, and perhaps I should go to sleep, but I want to finish this stuff quicker, so&amp;hellip;&lt;/p&gt;
&lt;p&gt;The chapter starts with a benchmark:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; Zoo {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  init() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.aardvark = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.baboon   = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.cat      = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.donkey   = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.elephant = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.fox      = 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ant()    { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.aardvark; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  banana() { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.baboon; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  tuna()   { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.cat; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  hay()    { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.donkey; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  grass()  { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.elephant; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mouse()  { &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.fox; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; zoo = Zoo();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; sum = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; start = clock();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (sum &amp;lt; 100000000) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sum = sum + zoo.ant()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            + zoo.banana()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            + zoo.tuna()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            + zoo.hay()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            + zoo.grass()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            + zoo.mouse();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print sum;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this on the reference implementation takes &lt;code&gt;3.87092&lt;/code&gt; seconds and the result is &lt;code&gt;1e+08&lt;/code&gt; or &lt;code&gt;100000000&lt;/code&gt;.
Running on the release build of my language takes &lt;code&gt;8.065999984741211&lt;/code&gt;, and the result is &lt;code&gt;100000002&lt;/code&gt;.
Don&amp;rsquo;t mind the difference, it&amp;rsquo;s an IEEE 754 quirk - if we change how &lt;code&gt;clox&lt;/code&gt; prints it&amp;rsquo;s value from scientific notation to plain float, we&amp;rsquo;ll get the same thing.&lt;/p&gt;
&lt;p&gt;Now, my implementation is twice as slow.
Thankfully, the loop itself is fast - if we just do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; sum = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; start = clock(); &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (sum &amp;lt; 100000000) { sum = sum + 1 + 1 + 1 + 1 + 1 + 1; } print clock() - start;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.2915e+01
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ziglox&amp;gt;  print sum;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.00000002e+08
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The speed is comparable.&lt;/p&gt;
&lt;p&gt;Unfortunately, I am lazy.
The book proceeds at optimizing table lookups, by using bit-masking instead of the modulo operator.
I&amp;rsquo;m not using the table implementation from the book itself - instead, I&amp;rsquo;m wrapping Zig&amp;rsquo;s &lt;code&gt;std.hash_map.HashMap&lt;/code&gt;.
Fortunately, Zig&amp;rsquo;s &lt;code&gt;HashMap&lt;/code&gt; already uses bit-masking:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// Find the index containing the data for the given key.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// Whether this function returns null is almost always
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// branched on after this function returns, and this function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// returns null/not null from separate code paths.  We
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// want the optimizer to remove that branch and instead directly
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// fuse the basic blocks after the branch to the basic blocks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// from this function.  To encourage that, this function is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;/// marked as inline.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; getIndex(self: Self, key: anytype, ctx: anytype) ?&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; verifyContext(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(ctx), &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(key), K, Hash, &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.size == 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// If you get a compile error on this line, it means that your generic hash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// function is invalid for these parameters.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; hash = ctx.hash(key);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// verifyContext can&amp;#39;t verify the return type of generic hash functions,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// so we need to double-check it here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(hash) != Hash) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@compileError&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Context &amp;#34;&lt;/span&gt; ++ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(ctx)) ++ &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; has a generic hash function that returns the wrong type! &amp;#34;&lt;/span&gt; ++ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(Hash) ++ &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; was expected, but found &amp;#34;&lt;/span&gt; ++ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(hash)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; mask = self.capacity() - 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; fingerprint = Metadata.takeFingerprint(hash);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Don&amp;#39;t loop indefinitely when there are no empty slots.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; limit = self.capacity();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; idx = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@truncate&lt;/span&gt;(hash &amp;amp; mask));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;var&lt;/span&gt; metadata = self.metadata.? + idx;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt; (!metadata[0].isFree() &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; limit != 0) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (metadata[0].isUsed() &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; metadata[0].fingerprint == fingerprint) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; test_key = &amp;amp;self.keys()[idx];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// If you get a compile error on this line, it means that your generic eql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// function is invalid for these parameters.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; eql = ctx.eql(key, test_key.*);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// verifyContext can&amp;#39;t verify the return type of generic eql functions,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// so we need to double-check it here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(eql) != &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@compileError&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Context &amp;#34;&lt;/span&gt; ++ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(ctx)) ++ &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; has a generic eql function that returns the wrong type! bool was expected, but found &amp;#34;&lt;/span&gt; ++ &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeName&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(eql)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (eql) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; idx;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        limit -= 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idx = (idx + 1) &amp;amp; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        metadata = self.metadata.? + idx;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Assuming that it is as fast, let&amp;rsquo;s look at another optimization: NaN Boxing.&lt;/p&gt;
&lt;p&gt;Now, this is something completely new to me - I&amp;rsquo;m not sure if I ever heard of it.
Anyway, now we need to re-implement the &lt;code&gt;Value&lt;/code&gt; struct:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; NanBoxedValue = &lt;span style=&#34;font-weight:bold&#34;&gt;packed&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    data: &lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; SIGN_BIT: &lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt; = 0x8000000000000000;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; QNAN: &lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt; = 0x7ffc000000000000;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Nil = NanBoxedValue{ .data = QNAN | 1 };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; True = NanBoxedValue{ .data = QNAN | 3 };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; False = NanBoxedValue{ .data = QNAN | 2 };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We start with defining some constants.
Previously, &lt;code&gt;Nil&lt;/code&gt;, &lt;code&gt;True&lt;/code&gt;, and &lt;code&gt;False&lt;/code&gt; were top-level constants, but I&amp;rsquo;ve moved them into the struct, so then we could get the correct ones via a compile-time alias.
I did the same with the &lt;code&gt;UnionValue&lt;/code&gt; struct, previously named &lt;code&gt;Value&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, we need to reimplement the &lt;code&gt;is&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;, and &lt;code&gt;from&lt;/code&gt; methods.
I&amp;rsquo;m glad that I made them generic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; NanBoxedValue = &lt;span style=&#34;font-weight:bold&#34;&gt;packed&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; is(self: NanBoxedValue, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; target: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(.enum_literal)) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@hasField&lt;/span&gt;(ObjType, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@tagName&lt;/span&gt;(target))) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Obj)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; o = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(*Obj, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrFromInt&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.data &amp;amp; ~(SIGN_BIT | QNAN)))));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; o.objType == target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (target) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Bool =&amp;gt; (self.data &amp;amp; False.data) == False.data,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Nil =&amp;gt; self.data == Nil.data,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Number =&amp;gt; (self.data &amp;amp; QNAN) != QNAN,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Obj =&amp;gt; (self.data &amp;amp; (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; as(self: NanBoxedValue, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; T: &lt;span style=&#34;font-weight:bold&#34;&gt;type&lt;/span&gt;) T {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@hasField&lt;/span&gt;(ObjType, typeNameUnqualified(T)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(*Obj, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrFromInt&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.data &amp;amp; ~(SIGN_BIT | QNAN))))).as(&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@typeInfo&lt;/span&gt;(T)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Pointer =&amp;gt; |p| p.child,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; T,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (T) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(self.data)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; =&amp;gt; self.data == True.data,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; =&amp;gt; Nil.data,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            *Obj =&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(*Obj, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@ptrFromInt&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;usize&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intCast&lt;/span&gt;(self.data &amp;amp; ~(SIGN_BIT | QNAN))))),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;inline&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; from(x: anytype) NanBoxedValue {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@TypeOf&lt;/span&gt;(x)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;i32&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime_int&lt;/span&gt; =&amp;gt; NanBoxedValue{ .data = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@floatFromInt&lt;/span&gt;(x)))) },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;comptime_float&lt;/span&gt; =&amp;gt; NanBoxedValue{ .data = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;u64&lt;/span&gt;, &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@bitCast&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@as&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;, x))) },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (x) True &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; False,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; =&amp;gt; Nil,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            *Obj =&amp;gt; NanBoxedValue{ .data = SIGN_BIT | QNAN | &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@intFromPtr&lt;/span&gt;(x) },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; =&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unreachable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, we need the remaining &lt;code&gt;isFalse&lt;/code&gt;, &lt;code&gt;format&lt;/code&gt;, &lt;code&gt;equal&lt;/code&gt;, and &lt;code&gt;mark&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; NanBoxedValue = &lt;span style=&#34;font-weight:bold&#34;&gt;packed&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; isFalsey(self: NanBoxedValue) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Bool)) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; !self.as(&lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Nil)) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; equal(self: NanBoxedValue, other: NanBoxedValue) &lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Number) &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; other.is(.Number)) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.as(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;) == other.as(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; self.data == other.data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; mark(self: NanBoxedValue, vm: *VM) !&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Obj))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.as(*Obj).mark(vm);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; format(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self: NanBoxedValue,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;comptime&lt;/span&gt; fmt: []&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;u8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        options: std.fmt.FormatOptions,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        out_stream: anytype,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ) !&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _ = fmt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _ = options;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Number)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; out_stream.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{d}&amp;#34;&lt;/span&gt;, .{self.as(&lt;span style=&#34;font-weight:bold&#34;&gt;f64&lt;/span&gt;)});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Bool)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; out_stream.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;, .{self.as(&lt;span style=&#34;font-weight:bold&#34;&gt;bool&lt;/span&gt;)});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (self.is(.Nil)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; out_stream.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nil&amp;#34;&lt;/span&gt;, .{});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; self.as(*Obj).print(out_stream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that we&amp;rsquo;re no longer using a constant dispatch on the enum tag - instead, it&amp;rsquo;s a chain of &lt;code&gt;if&lt;/code&gt; &lt;code&gt;else&lt;/code&gt;.
Well, that is a small price to pay, as we rarely print things, compared to overall execution.&lt;/p&gt;
&lt;p&gt;After implementing this type of &lt;code&gt;Value&lt;/code&gt; struct, we can tell the rest of the implementation to use it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; Value = &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; (NAN_BOXING) NanBoxedValue &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; UnionValue;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the rest of the code, hopefully, works.
I had to make some small adjustments though.&lt;/p&gt;
&lt;p&gt;Now, running the benchmark shows takes &lt;code&gt;5.4649999141693115&lt;/code&gt; seconds.
A great improvement!&lt;/p&gt;
&lt;h2 id=&#34;thoughts-on-the-book&#34;&gt;Thoughts on the book&lt;/h2&gt;
&lt;p&gt;The book is great.
The writing style is engaging, I really liked the diagrams, and the material is properly structured.
Would recommend.
This is my second read, mind you.&lt;/p&gt;
&lt;p&gt;Perhaps, I was too harsh at times, but I just was frustrated with some things and let it out.&lt;/p&gt;
&lt;p&gt;Now, I do think that the lack of arrays, and plain hash tables is a bit of a bummer.
I get it - it is a learning exercise, but, it would be great to have just a bit more from actual languages.
Also, it would be really interesting to look at JIT and FFI, but I guess it deserves its own book already.&lt;/p&gt;
&lt;p&gt;All in all, I&amp;rsquo;m glad that I read this book.
It allowed me to tighten my Clojure skills in the past, and learn an awesome language today - Zig.&lt;/p&gt;
&lt;h2 id=&#34;thoughts-on-zig&#34;&gt;Thoughts on Zig&lt;/h2&gt;
&lt;p&gt;I really like Zig.&lt;/p&gt;
&lt;p&gt;At times I thought to myself - I am enjoying this way too much.
As you may know, I was a C programmer before, and I did some pretty low-level stuff in it.
I got tired of C and decided that I didn&amp;rsquo;t want to write in these kinds of languages.
Rust gave me hope, but it fell apart before my eyes.&lt;/p&gt;
&lt;p&gt;Zig, however, is a C I always wanted.
With a type system that actually helps reading and writing code, and not intended to do some convoluted nonsense.
I&amp;rsquo;ve written all of the code without an LSP, and it was a breeze.
The only tooling I used, besides the compiler, was Emacs tags.
Generating tags isn&amp;rsquo;t supported, and their precision is limited, but it was enough for this project.
If you&amp;rsquo;re interested, here&amp;rsquo;s how I generated the &lt;code&gt;TAGS&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;First, I made these regex rules for &lt;code&gt;etags&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/.*\&amp;lt;fn +\([a-zA-Z0-9_]+\) *(/\1/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/.*\&amp;lt;\(var\|const\) *\([a-zA-Z0-9_]+\) *= *\(extern\|packed\)? *\(struct\|enum\|union\)/\2/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/.*\&amp;lt;error +\([a-zA-Z0-9_]+\)/\1/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  zig.etags
&lt;/div&gt;
&lt;p&gt;And added this to &lt;code&gt;Makefile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ZIG_STD&lt;/span&gt; ?= ~/.zig/lib/std
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ZIG_STD_SOURCES&lt;/span&gt; := &lt;span style=&#34;font-weight:bold&#34;&gt;$(&lt;/span&gt;shell find &lt;span style=&#34;font-weight:bold&#34;&gt;$(&lt;/span&gt;ZIG_STD&lt;span style=&#34;font-weight:bold&#34;&gt;)&lt;/span&gt; -type f -name &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;*.zig&amp;#39;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ZIG_SOURCES&lt;/span&gt; := &lt;span style=&#34;font-weight:bold&#34;&gt;$(&lt;/span&gt;shell find ./src/zig -type f -name &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;*.zig&amp;#39;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tags&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	etags --language=none --regex=@zig.etags &lt;span style=&#34;font-weight:bold&#34;&gt;$(&lt;/span&gt;ZIG_SOURCES&lt;span style=&#34;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;$(&lt;/span&gt;ZIG_STD_SOURCES&lt;span style=&#34;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works well enough and allows jumping to the standard library.
I don&amp;rsquo;t use automatic completion that much even in other languages, and error checking is fine when I compile code.
Like old times.&lt;/p&gt;
&lt;p&gt;Sometimes the errors are weird:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zig build -Doptimize=Debug -p ./target/zig --cache-dir ./target/zig/.cache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zig build-exe lox-0.1.77 Debug native: error: the following command failed with 1 compilation errors:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;~/Downloads/zig-linux-x86_64-0.11.0/zig build-exe ~/Git/lox/src/zig/lox/main.zig --cache-dir ./target/zig/.cache --global-cache-dir ~/.cache/zig --name lox-0.1.77 --listen=-
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Build Summary: 0/3 steps succeeded; 1 failed (disable with --summary none)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;install transitive failure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+- install lox-0.1.77 transitive failure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   +- zig build-exe lox-0.1.77 Debug native 1 errors
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;~/Downloads/zig-linux-x86_64-0.11.0/lib/std/fmt.zig:87:9: error: expected tuple or struct argument, found void
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Like, OK, where exactly is the error though?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the source code that generates the message above.
Can you spot the problem?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-zig&#34; data-lang=&#34;zig&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; std = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;@import&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;std&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;pub&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt; main() !&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; stdout = std.io.getStdOut().writer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;try&lt;/span&gt; stdout.print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Hello, world!&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, {});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yup, I forgot the &lt;code&gt;.&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are other such errors, I just didn&amp;rsquo;t bother to save more.&lt;/p&gt;
&lt;p&gt;Zig&amp;rsquo;s build system is something else.
Can&amp;rsquo;t say I like it, but I don&amp;rsquo;t dislike it either.
I guess I need to spend a bit more time with it to say for sure.
The inability to set the cache and target directories from &lt;code&gt;build.zig&lt;/code&gt; is a bummer though.&lt;/p&gt;
&lt;p&gt;Also, the language name is, well, weird.
The Crafting Interpreters book starts by explaining why the language is called Lox.
In the &lt;a href=&#34;http://craftinginterpreters.com/introduction.html#design-note&#34; target=&#34;_blank&#34;&gt;design note&lt;/a&gt; they mention Nim:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;It doesn’t have negative connotations across a number of cultures.
This is hard to be on guard for, but it’s worth considering.
The designer of Nimrod ended up renaming his language to “Nim” because too many people remember that Bugs Bunny used “Nimrod” as an insult.
(Bugs was using it ironically.)&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, the name &amp;ldquo;Zig&amp;rdquo;, in my country at least, &lt;em&gt;sounds&lt;/em&gt; a lot like the beginning of a &lt;a href=&#34;https://en.wikipedia.org/wiki/Nazi_salute&#34; target=&#34;_blank&#34;&gt;Nazi salute&lt;/a&gt;.
And when translated and spelled it has literally the same letters.
I&amp;rsquo;m sure it is not intentional, but I had a hard time talking about this language to basically anyone.
Literally, everyone was like: &amp;ldquo;name&amp;rsquo;s weird&amp;rdquo;.
So I started calling it ZigLang instead.&lt;/p&gt;
&lt;p&gt;Apart from that, I really enjoy this language, and maybe will use it for other projects in the future.&lt;/p&gt;
&lt;h2 id=&#34;closing-thought&#34;&gt;Closing thought&lt;/h2&gt;
&lt;p&gt;Thank you for reading through this insanely enormous flow of consciousness.
And if you did not read it fully, I appreciate that you still got to the end.
Even if you just scrolled past everything.&lt;/p&gt;
&lt;p&gt;This post was about two years in the making.
I&amp;rsquo;m really glad that I&amp;rsquo;ve finally finished it, and I hope it is interesting and informative.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in the project&amp;rsquo;s source code, you can find it here: &lt;a href=&#34;https://gitlab.com/andreyorst/lox&#34; target=&#34;_blank&#34;&gt;lox&lt;/a&gt;.
And if you&amp;rsquo;re a seasoned Zig developer, I would appreciate it if you reviewed the code.
I am by no means an expert in Zig, so I probably made a lot of stupid decisions.&lt;/p&gt;
&lt;p&gt;Let me know what you think!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;because even this didn&amp;rsquo;t work later and I just symlinked the source directory into tests, because of course&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Common Lisp is compiled to native code and loaded without requiring application restart.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Just call them the homework.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Technically, there&amp;rsquo;s more, but there are no sub-scopes like in other languages.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Thoughts on Crafting Interpreters - Part 2&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 15 Jan 2024 07:02:00 +0300</pubDate>
    </item><item>
      <title>2023 Recap</title>
      <link>https://andreyor.st/posts/2023-12-31-recap/</link>
      <guid>https://andreyor.st/posts/2023-12-31-recap/</guid>
      <description>&lt;p&gt;This year certainly was a productive one for me.
I&amp;rsquo;ve written ~40 posts, have many more in the works, made a few new projects in Fennel and Clojure, and changed more of how I spend my time overall.
The last year&amp;rsquo;s recap I mentioned that I&amp;rsquo;m no longer available on most social networks - this certainly helps me keep a more healthy mental state.
I feel that I can keep my focus for longer, and overall my thoughts feel more structured than before.
Perhaps, reading books also had something to do with that, but I want to think that leaving social networks helped with that too.&lt;/p&gt;
&lt;h2 id=&#34;this-year-s-events&#34;&gt;This year&amp;rsquo;s events&lt;/h2&gt;
&lt;p&gt;Here are events and things in general that I think were impactful to me during this year:&lt;/p&gt;
&lt;h3 id=&#34;llms&#34;&gt;LLMs&lt;/h3&gt;
&lt;p&gt;This is the year we saw the rise of Large Language Models.
It was fun playing with ChatGPT for a few hours, but nothing that ultimately caught my interest for long enough.
Unfortunately, however, the world took way too much liking for LLMs, and now it polluted so many things that I started thinking about leaving not only the social networks but the internet completely.
How often do we see a tech that can do that?&lt;/p&gt;
&lt;p&gt;Let me explain what I mean, and why I think the net becomes less usable.&lt;/p&gt;
&lt;p&gt;As I browsed the net, I started suspecting that a lot of articles and posts that were previously written by copywriters now is seemingly written by LLMs.
A lot of reviews and comparison articles, of all things, are now written by LLMs.
Automated mail that I receive is now written by LLMs.
Even freakin&amp;rsquo; art is now drawn by LLMs.&lt;/p&gt;
&lt;p&gt;There were reports that people lost their jobs due to big companies realizing that a single LLM can replace a handful of people, and the quality of the result won&amp;rsquo;t change as much.
Well, I mean, if such a company makes such a move, perhaps their products weren&amp;rsquo;t worth my time even before that, but still.
LLMs are killing the net, and subsequently the software.
For now, at least.&lt;/p&gt;
&lt;p&gt;AI, in general, is a weird thing.
It&amp;rsquo;s certainly in its infancy, but it is already capable of a lot of things.
I just think that we&amp;rsquo;re applying it the wrong way.
Certainly, an AI that can reason about hard-to-grasp problems is an interesting field, but what we&amp;rsquo;re largely doing with AI today is not that.
Maybe there&amp;rsquo;s a need for another AI winter to better spend the resources we&amp;rsquo;re given?&lt;/p&gt;
&lt;h3 id=&#34;gamedev&#34;&gt;Gamedev&lt;/h3&gt;
&lt;p&gt;I finally tipped my toes into the game dev field.
It was fun, but exhausting, though that&amp;rsquo;s mostly on me - I had a bright idea to impose myself with a 6-month marathon.
Looking back on it, the idea wasn&amp;rsquo;t half bad, I just needed more time.
A resource I don&amp;rsquo;t have as much as I&amp;rsquo;d like to.&lt;/p&gt;
&lt;p&gt;In the next year, I hope to do more game dev stuff, but I won&amp;rsquo;t probably do it this way.
I have two project ideas I wanted to make for a long time.
Yet, I know that the dream project shouldn&amp;rsquo;t be your first project, or else you would probably damage it without any way to repair it afterward.
So we&amp;rsquo;ll see.
I&amp;rsquo;m not sure that I really want to become a full-time game developer hobbyist yet.&lt;/p&gt;
&lt;h3 id=&#34;fennel&#34;&gt;Fennel&lt;/h3&gt;
&lt;p&gt;Fennel, again, was a big part of this year.
I haven&amp;rsquo;t worked on the compiler at all though, I think the only thing I did was metadata-related stuff.
However, I did a lot of projects in Fennel, the already-mentioned games, and some new libraries.&lt;/p&gt;
&lt;p&gt;However, I noticed that I&amp;rsquo;m starting to get tired of Fennel - it&amp;rsquo;s a nice project and makes Lua more fun, but it has a lot of quirks that I simply learned to accept.
After trying to teach a friend to program in Fennel I&amp;rsquo;ve realized how many things you can stumble on, I just don&amp;rsquo;t notice these anymore.
Not because they&amp;rsquo;re harmless, just because I already know how exactly these things need to be written.
Most of these are fennel-specific, actually, so I even tried writing in pure Lua for a kick, but didn&amp;rsquo;t like it as much.
Although I still like Lua as a runtime.&lt;/p&gt;
&lt;p&gt;I still need to reflect on this more, I think.&lt;/p&gt;
&lt;h3 id=&#34;music&#34;&gt;Music&lt;/h3&gt;
&lt;p&gt;I started working on a proper setup for music listening.
I&amp;rsquo;m not yet ready to buy all these expensive amplifiers, turntables, and stuff, but I finally got myself a great pair of open-back headphones for critical listening.
Now I want to build my own music library, and probably leave music streaming services.
Or at least to use them only for discovering new artists, not as a general way to listen to music.&lt;/p&gt;
&lt;p&gt;I wouldn&amp;rsquo;t call myself an audiophile, but a lot of releases there have audible compression artifacts when listened to through proper equipment.
That&amp;rsquo;s not an issue when I&amp;rsquo;m listening to music on the go, but when I want to listen to music at home, I dedicate an hour to it and try to listen to all of the nuances, and sometimes these ruin the vibe.
This is also why I&amp;rsquo;m interested in vinyl - I like the vibes of manually setting up a record, and then listening to it until it ends.
But this requires a dedicated place in the house to place both the records and the turntable with all of its equipment, which I don&amp;rsquo;t yet have.&lt;/p&gt;
&lt;h3 id=&#34;books&#34;&gt;Books&lt;/h3&gt;
&lt;p&gt;Not long before the end of the year, I started reading some management-related books.
There&amp;rsquo;s a reason for that - I&amp;rsquo;m preparing for the lead position at my company, and this requires a lot more skill than just programming language and project knowledge.&lt;/p&gt;
&lt;p&gt;Strangely, I&amp;rsquo;ve noticed that there&amp;rsquo;s a certain misconception in the tech companies, at least with the ones I had contact with.
A lot of times a team leader is someone who&amp;rsquo;s skills are just higher than others in the team.
E.g. you have this kind of career ladder:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Trainee;&lt;/li&gt;
&lt;li&gt;Junior;&lt;/li&gt;
&lt;li&gt;Middle;&lt;/li&gt;
&lt;li&gt;Senior;&lt;/li&gt;
&lt;li&gt;Team leader??&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I mean, sure, you&amp;rsquo;re a skilled programmer by the time you&amp;rsquo;ve reached a Senior position, and you sure know a lot about projects, but how exactly this will help you lead people?
Unless you know basic psychology, how to work with people, how to properly give feedback, how to effectively motivate, and how to help people grow you&amp;rsquo;re not a team leader (in my eyes), you&amp;rsquo;re just a person with a project map.
A good team leader should not necessarily be a great programmer, it&amp;rsquo;s a whole different field, that requires a separate education.&lt;/p&gt;
&lt;p&gt;Unless we&amp;rsquo;re talking about a technology leader, of course, and some companies mix these two positions into one and hence require that the team leader has great tech skills.
But tech skills are simply not enough to be a good team leader.
Tell you what - a great team leader makes it so every team member &lt;em&gt;sincerely&lt;/em&gt; wants to do their best, and also are generally happier and feel like a real team.&lt;/p&gt;
&lt;h3 id=&#34;games&#34;&gt;Games&lt;/h3&gt;
&lt;p&gt;I have almost finished my PlayStation 4 backlog of games I bought during the years.
Finally, I mean, FINALLY, managed to beat Isshin Ashina in Sekiro Shadows Die Twice.
Took me several days.
I haven&amp;rsquo;t bought more games on this platform though, as newer games are already mostly targeting the PlayStation 5, which I don&amp;rsquo;t have, and in general, newer games are less interesting to me.&lt;/p&gt;
&lt;p&gt;On the other hand, I&amp;rsquo;ve played a lot of cool games on the Nintendo Switch.
Finally got to play Metroid Prime, thanks to the recent remake/remaster.
The Legend of Zelda: Tears of the Kingdom was fun at first, but later I felt exhausted by mostly filler content in the depths.
Pikmin 3 was wonderful, did not expect that, although it was quite short.
Unfortunately, I wasn&amp;rsquo;t really inspired by Mario Wonder.
Even though it had a lot of seemingly crazy wonder stuff, it felt a bit empty and oddly paced.
For example, this year I also played DK Tropical Freeze for the first time, and even though I can&amp;rsquo;t say that I enjoyed every second, most of the playthrough was interesting, and the pacing felt much better, compared to Wonder.
Anyway, that&amp;rsquo;s just my point of view, you don&amp;rsquo;t have to agree or disagree, it&amp;rsquo;s not a review.&lt;/p&gt;
&lt;p&gt;What I can say, is that with age it becomes harder to invest time into games.
With each year I play fewer games, and I think that&amp;rsquo;s not uncommon.
However, the game industry tries to sell as many games as possible, and I see people with a lot of games in their Steam library that they haven&amp;rsquo;t played at all.
There&amp;rsquo;s even a term for collecting books but not reading them called &lt;a href=&#34;https://en.wikipedia.org/wiki/Antilibrary&#34; target=&#34;_blank&#34;&gt;Antilibrary&lt;/a&gt; or sometimes &lt;a href=&#34;https://en.wikipedia.org/wiki/Tsundoku&#34; target=&#34;_blank&#34;&gt;Tsundoku&lt;/a&gt;, and that practically what happens with games today for a lot of people.&lt;/p&gt;
&lt;p&gt;I stopped buying games a few years ago due to this happening to me too, and the only reason I recently started this again was that I got the Nintendo Switch.
Now I try to complete everything I buy, but I often find myself unable to invest in the game&amp;rsquo;s world.
Like, a lot of games now feel tedious, not interesting.
Usually, all I care about is the main plot, unless the side characters are interesting enough, and I don&amp;rsquo;t want a lore-dump every time I speak with a random person in the game.
So, like, it&amp;rsquo;s hard, but I do enjoy good stories in games, it just has to be compelling enough.
Maybe that&amp;rsquo;s the quality of today&amp;rsquo;s games, maybe it&amp;rsquo;s age, I don&amp;rsquo;t know.&lt;/p&gt;
&lt;h3 id=&#34;talks&#34;&gt;Talks&lt;/h3&gt;
&lt;p&gt;I gave some talks this year, mostly about Fennel.
It&amp;rsquo;s good that people are interested in Fennel, but I&amp;rsquo;ve already mentioned that once they try it, a lot are turned down by lots of nuances you have to keep in mind.&lt;/p&gt;
&lt;p&gt;I also took a small intensive course on giving talks.
Hopefully, my future talks will be better structured and more engaging.
I&amp;rsquo;ve set up a dedicated &lt;a href=&#34;https://andreyor.st/talks&#34;&gt;page&lt;/a&gt; where all of my talks are available.&lt;/p&gt;
&lt;h2 id=&#34;plans-for-the-next-year&#34;&gt;Plans for the next year&lt;/h2&gt;
&lt;p&gt;Now, I have a lot of plans, but it&amp;rsquo;s hard to decide upfront what exactly I will do.
I definitively want to do more game dev, albeit at a slower pace, and maybe in something less limiting than TIC-80.
Don&amp;rsquo;t get me wrong, though, TIC-80 is amazing.&lt;/p&gt;
&lt;p&gt;I also want to finish working through the Crafting Interpreters book, as I&amp;rsquo;m currently in the process of going through it.
Until then, no gamedev things will happen, probably.&lt;/p&gt;
&lt;p&gt;Speaking of, I thought about implementing my own language that transpiles to Lua.
Not that I dislike Fennel, I just want something both simple and more robust, as well as the fact that I simply want to try tackling this task myself.
It&amp;rsquo;s not exactly in the spirit of Crafting Interpreters, but I figured that there&amp;rsquo;s no point in creating a new runtime, unless you have some really interesting ideas to try.
It&amp;rsquo;s a good task for education, but I feel that today we have way too many languages, and, honestly, I often think that most of these are just rehashes of existing ones, because people did not like one thing or another in the original.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve mentioned that I&amp;rsquo;m thinking about leaving the net, and in fact, I actually have plans to do that.
In fact, I&amp;rsquo;m already incorporating some changes to how I live - for the most part, now I try to keep my laptop offline.
I won&amp;rsquo;t believe how less of a distraction it becomes this way!
So, for the next year, I&amp;rsquo;m planning to continue keeping it offline, only going to the net when I need to search for something.
I will make a proper post on this, once I have some results.
Wish me luck though!&lt;/p&gt;
&lt;p&gt;Additionally, I&amp;rsquo;m slowing down my response time by disabling notifications on my smartphone.
This means that if someone writes me a message or an email I won&amp;rsquo;t be notified of it until I decide to check.
I feel that this is a far less disturbing, and more productive model to use my phone.
Can&amp;rsquo;t keep it offline, like my laptop, but that alone is already helpful.
After all, emails and chats were meant to be asynchronous, so you should not assume that you&amp;rsquo;ll get the response instantly.&lt;/p&gt;
&lt;p&gt;Definitely going to continue reading more books.
Lately, I&amp;rsquo;ve started noticing that my general erudition is lacking, so I don&amp;rsquo;t know, but maybe alongside to tech and psychology books I will also try to squeeze in some classics.
Maybe I&amp;rsquo;ll even start a series of posts with a theme of reading reports where I list books I read, with some thoughts on each.&lt;/p&gt;
&lt;h2 id=&#34;ending-thoughts&#34;&gt;Ending thoughts&lt;/h2&gt;
&lt;p&gt;This post came out longer than usual.
Usual for a recap post, I mean.
Probably because this year had a lot of stuff happening.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;rsquo;m interested in your feedback!
Not on this particular post, but in general, I mean.
Recently I added a &amp;lsquo;Comment&amp;rsquo; button at the end of each post, that allows anyone to send me an email.
I already get emails from time to time, so I figured I&amp;rsquo;d help people reach me by providing a dedicated link for each post with the automatic subject so I could categorize these in my inbox.&lt;/p&gt;
&lt;p&gt;Such feedback often encouraged me throughout this year, and I&amp;rsquo;m trying to make this blog better based on your suggestions.
Maybe you want me to cover something, or maybe you completely disagree with something I said - I&amp;rsquo;m open to any kind of feedback.
All such conversations are private, so don&amp;rsquo;t be shy - if you have something to say, you can reach me!&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all from me for this year, so…
See you next year!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: 2023 Recap&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 31 Dec 2023 15:52:00 +0300</pubDate>
    </item><item>
      <title>We&#39;ve become overdependent on the net</title>
      <link>https://andreyor.st/posts/2023-12-26-weve-become-overdependent-on-the-net/</link>
      <guid>https://andreyor.st/posts/2023-12-26-weve-become-overdependent-on-the-net/</guid>
      <description>&lt;p&gt;The title says it all.&lt;/p&gt;
&lt;p&gt;No, really, I&amp;rsquo;m astonished at how much software is basically useless without an internet connection.
Net is no longer something additional to your daily tasks, it is essential for your daily tasks.&lt;/p&gt;
&lt;p&gt;Just recently, I installed GSConnect, a GNOME addon that implements the KDE Connect protocol.
I use the Fedora Silverblue, and perhaps it doesn&amp;rsquo;t come with Open SSL, so the GSConnect complains about it:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-12-26-weve-become-overdependent-on-the-net/Screenshot%20from%202023-12-26%2021-52-09.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Note the message: &amp;ldquo;Click for help troubleshooting&amp;rdquo;.
When clicked, instead of the help dialog, the browser is opened, automatically trying to visit GitHub wiki:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-12-26-weve-become-overdependent-on-the-net/Screenshot%20from%202023-12-26%2021-52-30.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;However, it fails, because my PC is not connected to the net.
What baffles me is that they know about the problem, they even have it on the Wiki, yet they refused to include a helpful message, instead requiring me to go to the web page.
This could have been summarized in the notification itself.&lt;/p&gt;
&lt;p&gt;Not so long ago, we bought a new laptop with Windows 11 on board.
It was not for my personal use, and as much as you may like to suggest that I should just install Linux on the machine, I can&amp;rsquo;t, and the person would not want to deal with it either.
What&amp;rsquo;s funny, though, was that the laptop refused to continue through the first boot welcome screen &lt;strong&gt;until&lt;/strong&gt; we connected it to the net.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s the problem, you may ask?
The problem was again the absence of a network around - the house did not have a PC for maybe five to ten years, so the net bill was pointless.
4G was fine enough on the tablet, and therefore when we bought a PC it could not connect to anything, because there wasn&amp;rsquo;t anything to connect to.
What makes things worse, the mobile provider provides unlimited traffic but forbids tethering it from the device, so we couldn&amp;rsquo;t even use that to turn the laptop on.&lt;/p&gt;
&lt;p&gt;Some people told me that if I press the connection button enough times, Windows gives up and lets you in without the net, but it didn&amp;rsquo;t work for me.
I guess this was either added in the later builds or was removed by that point.
The question is - why do I need the network connection to turn the device on at all?&lt;/p&gt;
&lt;p&gt;Smartphones are the same - buy a new phone, and it asks for a SIM card, then for WIFI, although it is possible to skip these things.
For now, at least.
Funnily enough, old cellular phones from the 90s and mid-2000s refused to boot without a SIM cart too.
Why?
Who knows.
Some even offered a &amp;ldquo;demo mode&amp;rdquo; - you could see what the phone can do, but could not use it until you put a SIM in.
Oh well.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s go back to the modern times.
A lot of smartphone apps refuse to work without an internet connection.
For example, when I used Spotify, on the premium plan you could download the music for offline listening.
However, when the network is unavailable, i.e. you&amp;rsquo;re offline, the app refuses to play the song.
Probably because it tries to connect to the server to check if your local date and server date are in sync, and if your premium plan is still active.
Or maybe it is just a poorly written app, but that can not be, I paid every month, and I suppose a lot of this money was spent on the app development.
Right?&lt;/p&gt;
&lt;p&gt;The subscription model is handy for businesses that want to constantly get a lot of money without that much effort.
For example, before the subscription model was a thing for Adobe products, each version of Photoshop featured a lot of additions and improvements justifying purchasing a new license.
Now, however, years go by, yet Photoshop still frequently crashes and doesn&amp;rsquo;t see substantial features, and a lot of different software is catching up feature-wise, further dis-justifying the subscription model.
Though, I don&amp;rsquo;t use Photoshop, so don&amp;rsquo;t take my word for anything I said - this information is provided by public reviews, and from some friends and coworkers who do have a subscription.
And yes, a subscription model is not directly tied to the topic of dependence on the net, however, you usually can&amp;rsquo;t use your software without periodic checks, and paying also requires the network.&lt;/p&gt;
&lt;p&gt;Another thing is the web apps.
I don&amp;rsquo;t use such apps often, but speaking of Photoshop reminded me of Figma.
It is not exactly a competitor, but it took away some of the userbase because it is a better fit for the task.
Again, probably, I don&amp;rsquo;t know why people use it, I, myself, don&amp;rsquo;t.
However, being a web application, it doesn&amp;rsquo;t really have an offline mode at all.
All your work is constantly synced with the server, and again, I&amp;rsquo;m not sure why - local storage is right there.&lt;/p&gt;
&lt;p&gt;Web technology has probably the fastest time-to-market so I can understand why it is probably better for a business to quickly publish a web app, instead of doing a proper desktop application.
But then again, these apps, even though they are emulating a desktop application, usually don&amp;rsquo;t stop at local features, and provide features that are dependent on the net.
For example, a recent rise in the popularity of Large Language Models resulted in a lot of apps including one as a &amp;ldquo;feature&amp;rdquo;.
But running these locally comes with a huge performance cost, not everyone would agree to pay, so instead they run by a huge server &lt;em&gt;somewhere&lt;/em&gt;, and are provided as a paid API subscription.
Now we have subscriptions that the app developer has to pay, and these apps usually use a subscription model too, meaning that in the end, you pay for the API, even if you don&amp;rsquo;t use it.&lt;/p&gt;
&lt;p&gt;I know, I know.
This may sound silly.
But just for a day, try to use your PC or, if you brave enough, a smartphone without an internet connection, and see how much work can be done.
The reason I&amp;rsquo;m writing this post is that I simply don&amp;rsquo;t have a network connection right now, so I just noticed this issue.
While I mostly do my work from Emacs, some apps still require a network, and I feel that I can&amp;rsquo;t use my PC to reach its full potential.
It&amp;rsquo;s a shame though, as most of the things I need the network for can be, and were done without it before.
Net just makes things easier.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: We&#39;ve become overdependent on the net&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 26 Dec 2023 22:56:00 +0300</pubDate>
    </item><item>
      <title>Janet</title>
      <link>https://andreyor.st/posts/2023-12-20-janet/</link>
      <guid>https://andreyor.st/posts/2023-12-20-janet/</guid>
      <description>&lt;p&gt;I decided to give &lt;a href=&#34;https://janet-lang.org&#34; target=&#34;_blank&#34;&gt;Janet&lt;/a&gt; another look - I&amp;rsquo;ve mentioned Janet before in this blog, and I have my thoughts on it.
However, I have never actually interacted with the language that much - I only read its documentation and some code.&lt;/p&gt;
&lt;p&gt;Recently, I found this interesting post: &lt;a href=&#34;https://ianthehenry.com/posts/my-kind-of-repl/&#34; target=&#34;_blank&#34;&gt;My Kind of REPL&lt;/a&gt; by Ian Henry.
It&amp;rsquo;s an interesting post, and I really liked the Braille plotting library they mentioned there.
So I wanted it for myself.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s not strong enough motivation to switch to Janet from Fennel or Clojure, so I decided to port this library to Clojure.
Yes, no Fennel this time.
To be honest, I noticed that my feelings towards Fennel are becoming a bit rusty.
Perhaps Janet&amp;rsquo;s author felt the same thing and made Janet after Fennel?&lt;/p&gt;
&lt;p&gt;Well, after a bit of searching, I found the library they&amp;rsquo;re talking about in the post: &lt;a href=&#34;https://github.com/ianthehenry/bytemap&#34; target=&#34;_blank&#34;&gt;bytemap&lt;/a&gt;.
The name is a bit confusing, I was expecting something like &lt;code&gt;braille-plot&lt;/code&gt; or &lt;code&gt;braillemap&lt;/code&gt; at least.
But it doesn&amp;rsquo;t matter - what does matter, is the ability to plot stuff in the REPL.
And the library is neat, with cool tricks to render points to the Braille symbols using bit-ops!
Kudos to Ian for implementing it!&lt;/p&gt;
&lt;p&gt;Now, I have a lot of experience porting Clojure code to Fennel and back, and I would say that the experience is seamless enough.
What I mean by that is that most of the forms can be used as is, or some simple text substitutions are required.
Most of these are substituting Fennel&amp;rsquo;s module separator &lt;code&gt;.&lt;/code&gt; with Clojure&amp;rsquo;s &lt;code&gt;/&lt;/code&gt;, and substituting &lt;code&gt;,&lt;/code&gt; in macros with &lt;code&gt;~&lt;/code&gt;.
There are more differences than that, of course, but one of the goals I had with &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; libraries was to allow copying code from Clojure to Fennel and back with as little changes as possible.
These two libraries provide most of the important Clojure behavior, and some of Clojure syntax to Fennel.&lt;/p&gt;
&lt;p&gt;Janet, on the other hand, &lt;a href=&#34;https://github.com/janet-lang/janet/blob/9eeefbd79a300aba5b5f430c94c7ecd4001b64b1/README.md#is-this-a-clojure-port&#34; target=&#34;_blank&#34;&gt;says that it is not a Clojure port&lt;/a&gt;, and lists all differences that come with that.
On the other hand, their standard library is far more rich than Fennels, and there are a lot of inspirations taken from Clojure as far as I can see.
So that&amp;rsquo;s good.&lt;/p&gt;
&lt;p&gt;I mentioned that apart from small syntactic changes, Fennel code can be ported to Clojure fairly easily.
With Janet, the situation is a bit different.
Say, here&amp;rsquo;s some Fennel code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qux&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or was it Clojure code?
In fact, this code will work in the same way in both languages.
Now, let&amp;rsquo;s look at the same code in Janet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qux&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, this code is different, however, it &lt;em&gt;will&lt;/em&gt; work in Clojure, yet with a subtle difference.
What is the difference you ask?
Why, in Clojure &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are global bindings!&lt;/p&gt;
&lt;p&gt;Now, you might wonder, why I bring this up.
Well, I find this strange, but in Janet, all of the documentation is written using &lt;code&gt;def&lt;/code&gt; instead of &lt;code&gt;let&lt;/code&gt; which Janet also has.
And as a result, a lot of code in the wild is written like that.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s another mystery to me - why Janet author, who created Fennel before that, decided that using &lt;code&gt;def&lt;/code&gt; is the way to create local variables?
I mean, sure, &lt;code&gt;let&lt;/code&gt; introduces yet another scope into the code, but is it &lt;em&gt;that bad&lt;/em&gt;?
Anyhow, you can write this code in Janet in the same way as in Clojure or Fennel, but I&amp;rsquo;m yet to see &lt;code&gt;let&lt;/code&gt; used in Janet code in the wild.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in the full source code of the port, you can find it &lt;a href=&#34;https://gitlab.com/andreyorst/braille-plot&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;porting-janet-code-to-clojure&#34;&gt;Porting Janet code to Clojure&lt;/h2&gt;
&lt;p&gt;Janet uses &lt;code&gt;def&lt;/code&gt; to establish immutable lexically-scoped bindings, and &lt;code&gt;var&lt;/code&gt; to create mutable bindings.
It&amp;rsquo;s a bit similar to Fennel, where the &lt;code&gt;local&lt;/code&gt; (a much better name, TBH) is used for the same purpose as &lt;code&gt;def&lt;/code&gt; in Janet, and &lt;code&gt;var&lt;/code&gt; does the same thing.
However, when porting to Clojure we should remember that we don&amp;rsquo;t have mutable bindings of any kind.
So my first steps were to change all of the code to have correct Clojure syntax and replace all &lt;code&gt;var&lt;/code&gt; definitions with the use of &lt;code&gt;atom&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s such change illustrated on the &lt;code&gt;plot&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Janet                                                     ;; Clojure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-scale&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;named&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;axis&lt;/span&gt;]             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-scale&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;axis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)                                                    &amp;amp; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;axis&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:or&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;axis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;new &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))                                       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;new &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bounds&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;))                                        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bounds&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;axis&lt;/span&gt;                                                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;axis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;                                                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;]))                               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;                                                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])))                              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  # &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;we&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;don&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;want&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clip&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extreme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;off&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;,     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; we don&amp;#39;t want to clip the extreme values off the canvas,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  # &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;so&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;we&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;narrow&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;slightly&lt;/span&gt;                            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; so we narrow the y range slightly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))                        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)                                              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;                                                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spans&lt;/span&gt; -0.5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; 0.5 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inclusive!&lt;/span&gt;)                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; x spans -0.5 to 0.5 (inclusive!)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 1)) 0.5))                                    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 1)) 0.5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-scale&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; -2))                             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-scale&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; -2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0.5) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 1))                                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0.5) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0.5) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)])                                                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0.5) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt;                                                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))                                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; @&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))                                             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reset!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-canvas&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;))                                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-canvas&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s a quick demo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;braille-plot.core&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/sin&lt;/span&gt; [40 10] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/PI&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢀⠤⠖⠊⠒⠒⠤⡀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⢠⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡷⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢄&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠹⡉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢉⠝⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠘⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠊⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠑⢤⣀⣀⢀⣀⠤⠊⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Changes in the code so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Janet uses a &lt;code&gt;default&lt;/code&gt; macro to establish a default value, in case one wasn&amp;rsquo;t specified.
Here it works with the &lt;code&gt;&amp;amp;named&lt;/code&gt; attribute in the argument list.&lt;/p&gt;
&lt;p&gt;In Clojure, we use rest syntax &lt;code&gt;&amp;amp;&lt;/code&gt; together with the map destructuring syntax &lt;code&gt;{}&lt;/code&gt; to achieve the same style of argument list.
And to supply default values for named arguments, map destructuring supports &lt;code&gt;:or&lt;/code&gt; modifier that itself specifies a map of names to default values.&lt;/p&gt;
&lt;p&gt;Hence the change from &lt;code&gt;&amp;amp;named axis&lt;/code&gt; with &lt;code&gt;(default axis true)&lt;/code&gt; to &lt;code&gt;{:keys [axis] :or {axis true}}&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;for&lt;/code&gt; is a list comprehension in Clojure, so it was changed to &lt;code&gt;dotimes&lt;/code&gt; which has the closest semantic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Comments were changed to use &lt;code&gt;;;&lt;/code&gt; instead of &lt;code&gt;#&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All inline &lt;code&gt;def&lt;/code&gt; usage was replaced with &lt;code&gt;let&lt;/code&gt; binding multiple symbols.&lt;/p&gt;
&lt;p&gt;This introduced more nesting, but it&amp;rsquo;s not a problem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;var&lt;/code&gt; usage was replaced with the use of &lt;code&gt;atom&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To be clear, I should use &lt;code&gt;volatile!&lt;/code&gt; here, but this is a temporary change, and more people are familiar with &lt;code&gt;atom&lt;/code&gt;.
This change required changing &lt;code&gt;set&lt;/code&gt; to use &lt;code&gt;reset!&lt;/code&gt; as a means to update the atom.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I also had to replace the &lt;code&gt;new&lt;/code&gt; function name with &lt;code&gt;canvas&lt;/code&gt; because &lt;code&gt;new&lt;/code&gt; is a special form in Clojure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So even this small piece of code required a fair amount of changes.
The most annoying one was converting &lt;code&gt;def&lt;/code&gt; usage to an appropriate &lt;code&gt;let&lt;/code&gt; usage, as it involved a lot of manual copying.&lt;/p&gt;
&lt;p&gt;By the way, the original Janet code changes a lot of values in place.
This happens all over the code, and because of that, I had to use &lt;code&gt;atom&lt;/code&gt; in a few more places.
However, most of these mutations are not necessary, and we can use things like Clojure&amp;rsquo;s &lt;code&gt;update&lt;/code&gt;, that instead of modifying a collection, return a new one with the modifications.
So the second change to this code was to make the &lt;code&gt;canvas&lt;/code&gt; immutable,&lt;/p&gt;
&lt;p&gt;Now all of the functions that change the canvas accept it, and return a new, modified canvas:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-scale&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bounds&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xs&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 1)) 0.5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x-scale&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y-scale&lt;/span&gt; -2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0.5) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0.5) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cond-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve changed &lt;code&gt;plot&lt;/code&gt; to accept &lt;code&gt;canvas&lt;/code&gt; as the last argument instead of passing all of its options and creating it if it wasn&amp;rsquo;t passed.
So now we can just call &lt;code&gt;(plot math/sin)&lt;/code&gt; and get a sensible result.
This is another way to provide default arguments in Clojure - we create two bodies for the function, and if the function is called with less than the needed amount of arguments, it has a dedicated body that can call itself with additional arguments.
Neat!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve moved out the axis creation code into a separate function &lt;code&gt;draw-axis&lt;/code&gt; because it makes more sense to create a blank canvas and draw axies on it afterward.
Since we&amp;rsquo;re passing the canvas object through, gradually creating newer versions of it with each function, we can have it as a separate step.&lt;/p&gt;
&lt;p&gt;The final change here is the use of the &lt;code&gt;loop&lt;/code&gt; instead of the &lt;code&gt;dotimes&lt;/code&gt;.
This change is motivated by the fact that we need to change some state between iterations, but we don&amp;rsquo;t want to use mutable constructs such as &lt;code&gt;atom&lt;/code&gt;.
So instead, we create a binding &lt;code&gt;current-point&lt;/code&gt; and change it with each call to &lt;code&gt;recur&lt;/code&gt;.
And the same thing happens to the &lt;code&gt;canvas&lt;/code&gt; binding.
This is literally a recursion, except Clojure has to do it this way because JVM can&amp;rsquo;t optimize tail calls.&lt;/p&gt;
&lt;p&gt;And, it works!
We can now pass the canvas through multiple &lt;code&gt;plot&lt;/code&gt; calls:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;braille-plot.core&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; 42 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; 20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/sqrt&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/pow&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; 2)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/sqrt&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/pow&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; 2))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/sqrt&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/pow&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; 2)))) 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/sqrt&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;abs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;1 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;math/pow&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; 2))))) 2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-canvas&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⠤⠔⠒⠒⠒⠊⡗⠒⠒⠒⠢⠤⢄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠴⠒⠉⠁⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠉⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⢀⠴⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠤⡀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⡠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢄⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⡔⠁⠀⠀⠀⠀⠀⢀⣀⣠⠤⠔⠒⠒⠒⠊⠉⠉⠉⡏⠉⠉⠑⠒⠒⠒⠢⠤⢄⣀⡀⠀⠀⠀⠀⠀⠈⢢⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⡰⠁⠀⠀⣀⠤⠒⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠒⠤⣀⠀⠀⠈⢆⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⢠⠃⢀⠔⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠢⡀⠘⡄&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⢸⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡇&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⣏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⣹&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⢹⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⡏&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠸⡀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⢀⠇&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⢣⠀⠀⠉⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠀⠀⡜⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠈⢢⠀⠀⠀⠀⠀⠉⠑⠒⠲⠤⢄⣀⣀⣀⡀⠀⠀⠀⡇⠀⠀⢀⣀⣀⣀⡠⠤⠔⠒⠊⠉⠀⠀⠀⠀⠀⡔⠁⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⡏⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠘⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠃⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠑⢤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠤⠊⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠈⠒⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠓⠲⠤⢄⣀⣀⣀⡀⣇⣀⣀⣀⡠⠤⠔⠒⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  (the width of the outer unit circle depends on your Braille font)
&lt;/div&gt;
&lt;p&gt;The rest of the code was converted similarly.
Uses of &lt;code&gt;def&lt;/code&gt; were converted to &lt;code&gt;let&lt;/code&gt;, and in-place mutations were replaced with the use of immutable data structures API.&lt;/p&gt;
&lt;p&gt;ClojureScript came with its oddities.
Clojure 1.11.0 introduced the &lt;code&gt;clojure.math&lt;/code&gt; namespace that allows more portable code between implementations.
However, the &lt;code&gt;clojure.string&lt;/code&gt; namespace is still quite sparse.
For instance, here&amp;rsquo;s the function that generates the Braille symbols:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;braille&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;byte&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;encode&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2800&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;byte&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?&lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;String.&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;byte-array&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; TODO: maybe there&amp;#39;s a better way?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;new &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/Uint8Array&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-&amp;gt;js&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.decode&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;new &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/TextDecoder&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-&amp;gt;js&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bytes&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is pretty straightforward for Clojure, but in ClojureScript we have some shenanigans.
I program in ClojureScript quite infrequently, so this code is, perhaps, completely terrible, so reach me out if you know a better way of doing this.&lt;/p&gt;
&lt;h2 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;Well, Janet still feels weird as a language.
I mean, it feels like its syntax, with regards to special characters, went through the &lt;a href=&#34;https://en.wikipedia.org/wiki/Caesar_cipher&#34; target=&#34;_blank&#34;&gt;Caesar cipher&lt;/a&gt;: &lt;code&gt;#&lt;/code&gt; for comments, &lt;code&gt;;&lt;/code&gt; for splicing, &lt;code&gt;@&lt;/code&gt; for table mutability, &lt;code&gt;~&lt;/code&gt; for quasiquote &lt;code&gt;`&lt;/code&gt; for long strings, &lt;code&gt;|&lt;/code&gt; for short function notation.
Its use of &lt;code&gt;def&lt;/code&gt; is, well, unconventional, and code style, in general, is not &lt;em&gt;lispy&lt;/em&gt; enough.
I mean, Fennel isn&amp;rsquo;t a proper Lisp either, yet thanks to the runtime, it feels pretty natural, and its syntax doesn&amp;rsquo;t deviate &lt;em&gt;too far&lt;/em&gt; from established conventions.
It feels more mature than Fennel, but quirky at the same time.&lt;/p&gt;
&lt;p&gt;In the future, though, I&amp;rsquo;d like to take a closer look at Janet&amp;rsquo;s virtual machine.
Perhaps it can be used as a target for a language that I will personally like more.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Janet&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 20 Dec 2023 23:17:00 +0300</pubDate>
    </item><item>
      <title>GNOME Software</title>
      <link>https://andreyor.st/posts/2023-12-06-gnome-software/</link>
      <guid>https://andreyor.st/posts/2023-12-06-gnome-software/</guid>
      <description>&lt;p&gt;Have you tried using the GNOME Software?
This thing:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-12-06-gnome-software/gnome-software.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Do you use it?
Are you even using GNOME?&lt;/p&gt;
&lt;p&gt;Oh, sorry, I think should point this out, it&amp;rsquo;s kinda important - I&amp;rsquo;m asking the developers of GNOME Software.&lt;/p&gt;
&lt;p&gt;Because, apparently, they don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;OK, let&amp;rsquo;s start this post over.&lt;/p&gt;
&lt;div class=&#34;title-group&#34;&gt;
  &lt;h1 class=&#34;title&#34;&gt;GNOME Software&lt;/h1&gt;
  &lt;div class=&#34;sub-title&#34;&gt;
    &lt;div class=&#34;date&#34;&gt;
      &lt;time datetime=&#34;2023-12-06T19:12:00+0300&#34; class=&#34;post-date&#34; title=&#34;Last modified at Wed, Dec 6, 20:50, 2023&#34;&gt;
        Wed, Dec 6, 2023
      &lt;/time&gt;
    &lt;/div&gt;
    &lt;div class=&#34;tags&#34;&gt;
      &lt;span class=&#34;horizontal-links links&#34;&gt;
        &lt;a href=&#34;https://andreyor.st/categories/rant/&#34;&gt;@rant&lt;/a&gt;
        &lt;a href=&#34;https://andreyor.st/tags/gnome/&#34;&gt;GNOME&lt;/a&gt;
        &lt;a href=&#34;https://andreyor.st/tags/tools/&#34;&gt;tools&lt;/a&gt;
        &lt;span title=&#34;~1876 words&#34;&gt;~8 minutes read&lt;/span&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;GNOME Software, or, just, Software, is an application that &amp;ldquo;allows you to find and install new apps and system extensions and remove existing installed apps&amp;rdquo;.
I mean, that&amp;rsquo;s what description is given to it on the &lt;a href=&#34;https://apps.gnome.org/Software/&#34; target=&#34;_blank&#34;&gt;official project page&lt;/a&gt;.
It is preinstalled on most distributions that use the GNOME desktop environment, except for, maybe Ubuntu, which has its own store for applications.
But I&amp;rsquo;m not going to touch Ubuntu here, I don&amp;rsquo;t really want to touch Ubuntu at all, to be honest, although I have to use it five days a week.&lt;/p&gt;
&lt;p&gt;At home, I use the Fedora Silverblue.
I like Fedora, in my opinion, it is one of the finest out-of-the-box-oriented distributions today because of how pure it is.
No fancy patches, or extensions, just pure GNOME as it is.
In addition to that, the Silverblue variant is immutable, so in addition to providing pure GNOME, it barely provides anything else.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve picked Silverblue because I like to keep my system clean, and immutability helps tremendously.
Everything is either a Flatpak or lives inside the Podman container.
To be frank, even before I used Silverblue I had the same kind of workflow on the regular Fedora distribution, and the same applies to Ubuntu that I use at work.
If your system got messed up enough for you to care you can just delete the container, and recreate a new one, installing only the stuff you do actually require.
But I&amp;rsquo;m getting off track here.&lt;/p&gt;
&lt;p&gt;I feel that the fact that I&amp;rsquo;m using Fedora Silverblue is important for this post because this means that I&amp;rsquo;m using a distribution that I can&amp;rsquo;t make changes to.
Well, I can, of course, but I don&amp;rsquo;t do that.
Again, all my apps are either in Flatpaks or containers, so the system itself is barely different from the fresh installation.
I had installed updates, but these come from Fedora, so I&amp;rsquo;m assuming they know what they&amp;rsquo;re doing.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s get back to the topic - I install apps as Flatpaks quite often.
I do so using GNOME Software!&lt;/p&gt;
&lt;p&gt;And it is &lt;strong&gt;pain&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;I have used GNOME since 2008 or 2009, can&amp;rsquo;t remember that exactly, so I&amp;rsquo;m a seasoned Linux user.
I have used a lot of different distributions, and for the past five years, Fedora has been my daily driver because it is simple, reliable, and has everything I need.
And what it doesn&amp;rsquo;t have, I can build from sources in the container with my own hands, so I don&amp;rsquo;t give a shit about stuff like AUR, Nix, etc.
For simple stuff, like a &lt;a href=&#34;https://andreyor.st/posts/2023-11-19-linux-music-players/&#34;&gt;music player&lt;/a&gt;, Flatpak is more than enough, and for stuff like Emacs, I&amp;rsquo;m running a container with all my development tools.
And here comes GNOME Software.&lt;/p&gt;
&lt;p&gt;For the past decade, ever since GNOME Shell was released in 2011 I have been using it.
I had spent two years using KDE just to see if the grass was &lt;em&gt;kreener&lt;/em&gt; on the other side but returned to GNOME eventually.
And, for the past decade, I&amp;rsquo;ve been using GNOME Software.&lt;/p&gt;
&lt;p&gt;I mean, what, do you expect me to &lt;a href=&#34;https://andreyor.st/posts/2023-10-27-you-dont-need-a-terminal-emulator/&#34;&gt;open a terminal&lt;/a&gt; every time I need to install or update a package?
Sure, back in the day I did that when I used Arch, and Ubuntu before it, but honestly, I don&amp;rsquo;t care if I need to input &lt;code&gt;pm update&lt;/code&gt; in the shell or press an &amp;ldquo;Update&amp;rdquo; button in the GUI.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;terminal is faster and more convenient for managing packages&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, right.
And how am I supposed to go and look for the screenshots of the app I&amp;rsquo;m about to install on the terminal?
You could say it&amp;rsquo;s a silly reason, but during the post on Linux music players, I have done that a lot.
Of course, when I know exactly what app I need, I can go to the shell, and type out the command in a fraction of the time that it takes for GNOME Software to fully load and become responsive.
And that&amp;rsquo;s what brings me to the beginning of the post.&lt;/p&gt;
&lt;p&gt;Dear GNOME Software developers, tell me, do you use your application or do you install everything from the terminal anyway?&lt;/p&gt;
&lt;p&gt;I think that the developer should be, if not the main, but an active user of the project they&amp;rsquo;re developing.
That applies both to open source and what you do at work - because if not, you don&amp;rsquo;t know your own software.&lt;/p&gt;
&lt;p&gt;A theory is nothing without practice, and the same goes for software development.
The code is a theory.
You compile the code and verify that it is correct like any theory should be.
The application of that code is &lt;strong&gt;practice&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;And I feel that the GNOME Software developers don&amp;rsquo;t use the program they create.
Here&amp;rsquo;s why.&lt;/p&gt;
&lt;p&gt;As I said before, I use Fedora Silverblue, with everything installed as a Flatpak or inside a container, so the system is pretty much as if I just installed it.
I rarely shut down my laptop, instead, I put it to sleep (not even into hibernation) most of the time.
Now, imagine I want to go and install the Audacious music player.
I open Software and start typing &lt;code&gt;Audacious&lt;/code&gt;, and that&amp;rsquo;s what I see:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-12-06-gnome-software/loading.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I stare at this for a few seconds, check that my internet connection is working, and realize that it happened again - GNOME Software just doesn&amp;rsquo;t do anything.
I tried waiting for minutes, and the spinner didn&amp;rsquo;t go away.
So I closed the app.
I opened it again.
And I still see the damn thing spinning because you know what?
When you press the close button, the Software doesn&amp;rsquo;t actually close, it always runs in the background, for reasons.&lt;/p&gt;
&lt;p&gt;So I have to go into the System Monitor and &lt;code&gt;kill&lt;/code&gt; the damn thing.
I reopen it again, type &lt;code&gt;Audactions&lt;/code&gt;, after it finishes loading everything, and now I see the player:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-12-06-gnome-software/audacious.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;And this happens to me &lt;strong&gt;every single time&lt;/strong&gt;.
On a system, that is, according to its promise is immutable, and hence this should probably happen even at the stock installation.
And, you know what - it does!
I have recently reinstalled Fedora on one of the laptops I have and left it working for a while, checking periodically if GNOME Software will behave like that.
I didn&amp;rsquo;t have to wait for long, it happened the next day!&lt;/p&gt;
&lt;p&gt;So this bug can be reproduced, with a bit of patience, on a clear installation!
Yet, it haunts me for the last 5-6 years or so!
Aarrgh!
ARE YOU EVEN TESTING YOUR SOFTWARE AT ALL?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*​breathes​*&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Sorry, I&amp;rsquo;ve got too &lt;del&gt;angry&lt;/del&gt; dramatic even for my style of writing.
I&amp;rsquo;m not the only one who experiences this particular bug, among other bugs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A Reddit &lt;a href=&#34;https://old.reddit.com/r/Fedora/comments/tt04l1/hows_software_still_having_issues_like_these/&#34; target=&#34;_blank&#34;&gt;post&lt;/a&gt; describes this exact problem, and many others, specifically mentioning that they&amp;rsquo;re not new&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2007&#34; target=&#34;_blank&#34;&gt;bug report&lt;/a&gt; was submitted to the official issue tracker, outlining the same problem.
I like the comment there:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Without a log I’m afraid we can’t diagnose or fix the problem, so I’ll close this issue report for now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Can&amp;rsquo;t diagnose?
Seriously?
Have you even tried though?&lt;/p&gt;
&lt;p&gt;Seriously, as a software developer, I don&amp;rsquo;t understand this.
I mean, sure, sometimes I don&amp;rsquo;t want to deal with bugs I personally don&amp;rsquo;t have, and it is open source, so I don&amp;rsquo;t really have to do that, someone else can and is welcome to.
But to close the issue because there are no logs and it can&amp;rsquo;t be diagnosed, despite the fact that the issue exists?
Especially, when it hits multiple people.
I don&amp;rsquo;t get it.
Don&amp;rsquo;t try to explain me, I won&amp;rsquo;t get it, because it&amp;rsquo;s hard for me to get it, so I&amp;rsquo;ll close the discussion for now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Many &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1748&#34; target=&#34;_blank&#34;&gt;search&lt;/a&gt; &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1243&#34; target=&#34;_blank&#34;&gt;related&lt;/a&gt; &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1185&#34; target=&#34;_blank&#34;&gt;requests&lt;/a&gt; are closed, yet the problem is still there.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s like they find a possible reason why this might happen, fix it, and close the issue without testing.
I mean, unless you can reproduce the bug before the fix, how would you know that it is fixed?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don&amp;rsquo;t know how the development process is organized in GNOME, especially for GNOME Software.
However, I think that they don&amp;rsquo;t actually use their own thing, because it has so many obvious bugs that I can hit several during a single session.
For instance, the Reddit post mentions this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While installing, the window &amp;ldquo;reloads&amp;rdquo; a couple of times, as if it was refreshing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yup, happens to me &lt;strong&gt;every time&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sometimes it feels like updates have been fetched, and the ones being displayed are the most recent, but updating only reveals those updates were not the newest ones and even updates need to be downloaded&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Happens to me as well.
To be more specific it happens like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You open the Software (that has been running in the background for long);&lt;/li&gt;
&lt;li&gt;You see that the &amp;ldquo;Updates&amp;rdquo; tab has a notification;&lt;/li&gt;
&lt;li&gt;You open the &amp;ldquo;Updates&amp;rdquo; tab and it shows a spinner;&lt;/li&gt;
&lt;li&gt;Then the updates appear.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I would assume, seeing the spinner, that it had fetched everything, but by pressing the &amp;ldquo;refresh&amp;rdquo; button, the spinner appears and goes for much longer, revealing that there are in fact more updates than there initially were.
Literally happened to me while I was writing the previous line, as I&amp;rsquo;m writing and testing at the same time.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1511&#34; target=&#34;_blank&#34;&gt;issue&lt;/a&gt;, that is closed on the tracker, but happens to me all the time, and is extremely easy to reproduce: while you install anything, the search stops working.
The funny thing, it is closed as a duplicate of the issue with the name &amp;ldquo;Rework threading model&amp;rdquo;, which supposedly should fix all of that.
However, how it is a duplicate?
At best it is blocked by that ticket, but it doesn&amp;rsquo;t duplicate it in any way because it describes the actual issue.
It should be closed only when the blocking issue is done, and the bug is tested to be gone.
What a mess.&lt;/p&gt;
&lt;p&gt;So, yeah, GNOME Software is full of bugs, as most of the software is today.
If you&amp;rsquo;ve seen the &amp;ldquo;Preventing the Collapse of Civilization&amp;rdquo; talk by Jonathan Blow, you may remember there was a moment where he listed all of the bugs that happened to him in the past few days.
Have a &lt;a href=&#34;https://youtu.be/ZSRHeXYDLko?t=1337&#34; target=&#34;_blank&#34;&gt;look&lt;/a&gt;, I&amp;rsquo;ve linked it with a timecode.&lt;/p&gt;
&lt;p&gt;So, why am I complaining in the blog and not actually submitting an issue?
Well, I don&amp;rsquo;t want to.
GNOME has a long history of ignoring problems, saying that people use their software in the wrong ways, and so on.
I just don&amp;rsquo;t want to go to their territory and be ignored too.
Instead, I can write a quick rant in my personal space, where I&amp;rsquo;m always right, and no one can prove me wrong, ha ha ha!
Obviously, I&amp;rsquo;m being sarcastic here, if you couldn&amp;rsquo;t tell.&lt;/p&gt;
&lt;p&gt;I guess, someday these bugs will be fixed, it&amp;rsquo;s just a shame that they have existed for so many years, and it seems like the developers don&amp;rsquo;t care.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s enough ranting for this year.
Use what you&amp;rsquo;re making, and test your fixes, or at least ask for feedback once you think you fixed the bug.
See ya!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: GNOME Software&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 06 Dec 2023 20:59:00 +0300</pubDate>
    </item><item>
      <title>Thoughts on Crafting Interpreters - Part 1</title>
      <link>https://andreyor.st/posts/2023-12-03-thoughts-on-crafting-interpreters-part-1/</link>
      <guid>https://andreyor.st/posts/2023-12-03-thoughts-on-crafting-interpreters-part-1/</guid>
      <description>&lt;p&gt;Today I would like to discuss the &lt;a href=&#34;http://craftinginterpreters.com/&#34; target=&#34;_blank&#34;&gt;Crafting Interpreters&lt;/a&gt; book by Robert Nystrom.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a book about designing an interpreter for a dynamic programming language called Lox.
Well, not exactly.
It&amp;rsquo;s split into two parts - in the first is about crafting a tree-walking interpreter, and the second is about writing a complete bytecode VM.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m also going to write two posts, one for each part of the book.
This particular one is on the first part, which I have completed a long time ago.
A year and a half, actually.
So most of the things I&amp;rsquo;m going to talk about here are not &lt;em&gt;fresh&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In the book, Robert chose Java as a language for the first half of the book.
The reasoning behind it is practical and well thought out, but I simply don&amp;rsquo;t like Java.
So instead, I chose Clojure as an implementation language, because I felt that it would be a good exercise, allowing me to sharpen my skills a bit more.&lt;/p&gt;
&lt;p&gt;TL;DR for this post could be:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Clojure is a nice language, and fits this kind of task well enough, as the tree-walking interpreter is largely a data-manipulation task.
Clojure&amp;rsquo;s protocols provide a great way of solving the expression problem with no boilerplate when compared to the Visitor pattern.
Immutability helps tremendously, eliminating bugs related to state management, with little, yet noticeable cost in performance, for this particular task, at least.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Plus a few complaints about the book.&lt;/p&gt;
&lt;p&gt;Now, if you&amp;rsquo;re interested in more, I welcome you to read the rest of the post.
But first, let&amp;rsquo;s get this straight - I&amp;rsquo;ll try to follow the book&amp;rsquo;s structure here, but no promises.
While the book is well-structured, it&amp;rsquo;s hard to reference specific parts of the code, as some pieces of the interpreter are changed frequently through the chapters.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m glad I&amp;rsquo;ve kept the repository around, as it contains all of the commit history, however, until the second part of the book I was loose on commit structure.
E.g. my commits for the first half look like&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a6f69c8 * use protocols to solve expression problem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7412fb2 * WIP AST
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4068faf * WIP parser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7990eb4 * support escapes in strings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;d9b3f02 * move tokenizer to its own namespace
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3d8a602 * add column info
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;186095f * tokenizer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While for the second half of the book it is structured much better:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;88dd209 * chapter 19: Strings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6116263 * chapter 18: Types of Values
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;742364c * chapter 17: Compiling Expressions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f1ceb50 * Chapter 16: Scanning on Demand
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;da0149c * chapter 15: A Virtual Machine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;f2d8a18 * chapter 14: Chunks of Bytecode
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, forgive me if I mix things up in this post - the second part will be better structured.
And, to be clear, this post isn&amp;rsquo;t really about the code, but about the book, although there&amp;rsquo;s plenty of code here.
I will highlight interesting differences in Clojure and Java approaches but I would not consider this the main topic of this post.&lt;/p&gt;
&lt;h2 id=&#34;scanning&#34;&gt;Scanning&lt;/h2&gt;
&lt;p&gt;For the first chapter, we start with scanning.
The chapter introduces various concepts, like error handling, but what I&amp;rsquo;d like to focus on here is token handling instead.&lt;/p&gt;
&lt;p&gt;In the book, Robert uses an enumeration type, which is probably how it is done in the Java world:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;com.craftinginterpreters.lox&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;enum&lt;/span&gt; TokenType {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Single-character tokens.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, I don&amp;rsquo;t know Java - never learned it for real, and went straight to Clojure.
So if you&amp;rsquo;re curious if it&amp;rsquo;s OK to go into Clojure without knowing Java first - it is.
Although, I did have some Scheme background.&lt;/p&gt;
&lt;p&gt;So unlike the Java solution, I went with Clojure&amp;rsquo;s way of enumerating things.
Maps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;single-token-type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\(&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left_paren&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\)&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right_paren&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\{&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left_brace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\}&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right_brace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:comma&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\-&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\+&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:plus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:semicolon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\*&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:star&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\=&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:equal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:less&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:greater&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\/&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:slash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\!&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bang&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same goes for all other token types.
It makes sense, as we&amp;rsquo;re essentially using the Enum as a lookup table for character dispatch.
Hence, instead of doing this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt; c = advance();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (c) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;(&amp;#39;&lt;/span&gt;: addToken(LEFT_PAREN); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;: addToken(RIGHT_PAREN); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;{&amp;#39;&lt;/span&gt;: addToken(LEFT_BRACE); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;}&amp;#39;&lt;/span&gt;: addToken(RIGHT_BRACE); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;: addToken(COMMA); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\(&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\)&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\{&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\}&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\-&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\+&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-token&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;single-token-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\=&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\!&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;gt;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In other words, we share the body for all cases, and do a character lookup in the table to get the token type.
This eliminates just a little bit of duplication.&lt;/p&gt;
&lt;p&gt;Another thing to note, which is more important in my opinion, is that this parsing process is stateless.
In the Java version, the &lt;code&gt;addToken&lt;/code&gt; method modifies this class state.
While handy, I don&amp;rsquo;t like this approach, it makes things harder to test.
My version uses a conventional Clojure &lt;code&gt;loop&lt;/code&gt; and simply adds tokens to the collection, which is then returned from the loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokenize&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at-end?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;complement &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial &amp;gt; &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; 0     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; current character&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; 1        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; current line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; []     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; tokens&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt;] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; error indication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at-end?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; when finished return a tuple containing tokens and error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; indication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; otherwise, we take the `nth` character from the source, and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; dispatch on it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nth &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\(&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\)&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\{&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\}&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\-&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\+&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Rebind the current char to the new `current` char;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Use the same line, as none of these introduce a line change;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Add new token to an immutable vector of `tokens`;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; pass `error?` as is, as no errors were introduced.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-token&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;single-token-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ... rest of the clauses follow the same idea ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, tokenization is fully self-contained, and doesn&amp;rsquo;t require any state - it just accepts the string.
I later added the column counting to this code, but it&amp;rsquo;s beside the point now.&lt;/p&gt;
&lt;h2 id=&#34;representing-code&#34;&gt;Representing Code&lt;/h2&gt;
&lt;p&gt;This chapter mostly goes on how to read and define a BNF-like grammar.
However, what&amp;rsquo;s really interesting is the second part of this chapter - generating the tree representation generation code.
It is often referred to as metaprogramming, i.e. programs writing programs.&lt;/p&gt;
&lt;p&gt;At first, I was puzzled by this - do we really need to write Java to generate some classes for us based on grammar?
Well, I mean, there are libraries that can do that at runtime without an issue, like &lt;a href=&#34;https://github.com/engelberg/instaparse&#34; target=&#34;_blank&#34;&gt;instaparse&lt;/a&gt;, but in this case, we&amp;rsquo;re generating stuff even before compilation.
In other words, the book suggests generating source code.&lt;/p&gt;
&lt;p&gt;Well, that&amp;rsquo;s just macros, I thought to myself, and after studying a bit what the intention is, I made the following macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-ast&lt;/span&gt; [&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;specs&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;list* &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;specs&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/split&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spec&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\s+:\s+&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/split&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;,?\s+&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;second&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;symbol &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     []))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defrecord &lt;/span&gt;~(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;symbol &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) ~&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fields&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It expands the following grammar into a list of record definitions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljloc.ast&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macroexpand-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-ast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Binary   : Expr left, Token operator, Expr right&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Grouping : Expr expression&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Literal  : Object value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Unary    : Token operator, Expr right&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/defrecord&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Binary&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;left &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/defrecord&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Grouping&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expression&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/defrecord&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Literal&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/defrecord&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unary&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However I realized that it is a bit overkill to do it this way, so I ditched the macro completely.
After all, writing these records requires much less work in Clojure than it is in Java, but we&amp;rsquo;ll get to that in a bit.&lt;/p&gt;
&lt;p&gt;For comparison, here&amp;rsquo;s a definition from the book:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;If&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;extends&lt;/span&gt; Stmt {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    If(Expr condition, Stmt thenBranch, Stmt elseBranch) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.condition = condition;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.thenBranch = thenBranch;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.elseBranch = elseBranch;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    @Override
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;R&amp;gt; R &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;accept&lt;/span&gt;(Visitor&amp;lt;R&amp;gt; visitor) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; visitor.visitIfStmt(&lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;final&lt;/span&gt; Expr condition;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;final&lt;/span&gt; Stmt thenBranch;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;final&lt;/span&gt; Stmt elseBranch;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s the Clojure version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defrecord &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;If&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;else&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, why does the book&amp;rsquo;s code appear to be more involved?&lt;/p&gt;
&lt;h3 id=&#34;the-visitor-pattern&#34;&gt;The Visitor pattern&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s a pretty specific problem, often appearing in projects, like this - the &lt;a href=&#34;https://en.wikipedia.org/wiki/Expression_problem&#34; target=&#34;_blank&#34;&gt;expression problem&lt;/a&gt;.
In the Java world, one of the solutions is the Visitor pattern, which the Book then &lt;a href=&#34;http://craftinginterpreters.com/representing-code.html#the-visitor-pattern&#34; target=&#34;_blank&#34;&gt;explains thoroughly&lt;/a&gt;.
I will not go into full details here, you&amp;rsquo;re free to read the book if you&amp;rsquo;re interested.&lt;/p&gt;
&lt;p&gt;The script, that generates classes for statements also generates methods required for the Visitor pattern to work.
We then can override these methods for each resulting type, and that&amp;rsquo;s basically it.
In the book, it is explained by defining a pretty printer for AST, printing parsed data as S-expressions.
Oh, sweet irony.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how it is done for the &lt;code&gt;Binary&lt;/code&gt; expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;com.craftinginterpreters.lox&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;AstPrinter&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;implements&lt;/span&gt; Expr.Visitor&amp;lt;String&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  String &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print&lt;/span&gt;(Expr expr) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; expr.accept(&lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;private&lt;/span&gt; String &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parenthesize&lt;/span&gt;(String name, Expr... exprs) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    StringBuilder builder = &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; StringBuilder();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    builder.append(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt;).append(name);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (Expr expr : exprs) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      builder.append(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      builder.append(expr.accept(&lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    builder.append(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; builder.toString();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Override
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;visitBinaryExpr&lt;/span&gt;(Expr.Binary expr) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; parenthesize(expr.operator.lexeme,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              expr.left, expr.right);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how it is done in Clojure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; protocols.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.protocols&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defprotocol &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IStringable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; ast.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.ast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.protocols&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:refer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IStringable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:import&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.tokenizer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defrecord &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Binary&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;, ^&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IStringable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;left &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(%s %s %s)&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s it.
But it doesn&amp;rsquo;t end here, because Clojure was designed in such a way that the expression problem is not a problem.&lt;/p&gt;
&lt;p&gt;We can extend other types with our protocol, even after these types are defined.
For, instance, here I extend the &lt;code&gt;Object&lt;/code&gt; to handle numbers, and any other objects, as well as &lt;code&gt;nil&lt;/code&gt; which is a special case for protocols in Clojure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-protocol&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IStringable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;double?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/replace&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\.0$&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nil&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:else&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;nil&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And there you have it - we don&amp;rsquo;t need the Visitor pattern in Clojure, and we&amp;rsquo;re free to extend existing methods with new classes at any point.
The book demonstrates that the pattern works by defining overrides for all other data types, and the following code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;(String[] args) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Expr expression = &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Expr.Binary(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Expr.Unary(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Token(TokenType.MINUS, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, 1),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Expr.Literal(123)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Token(TokenType.STAR, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;null&lt;/span&gt;, 1),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Expr.Grouping(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; Expr.Literal(45.67)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    System.out.println(&lt;span style=&#34;font-weight:bold&#34;&gt;new&lt;/span&gt; AstPrinter().print(expression));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which prints &lt;code&gt;(* (- 123) (group 45.67))&lt;/code&gt;.
We can do the same in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.ast&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ast/-&amp;gt;Binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ast/-&amp;gt;Unary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minus&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;123&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [0 0]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:star&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [0 0])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ast/-&amp;gt;Grouping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;45.67&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [0 0]))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(* (- 123) (do 45.67))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is different a bit, as I&amp;rsquo;m passing a line number and a column as a tuple &lt;code&gt;[0 0]&lt;/code&gt; but other than that it is the same.
If you&amp;rsquo;re wondering, &lt;code&gt;Token&lt;/code&gt; also implements the &lt;code&gt;IStringable&lt;/code&gt; protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defrecord &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Token&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;toString&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lexeme&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IStringable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lexeme&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ll see more of the protocols stuff in a bit, so let&amp;rsquo;s move on.&lt;/p&gt;
&lt;h2 id=&#34;parsing-expressions&#34;&gt;Parsing Expressions&lt;/h2&gt;
&lt;p&gt;The parser described in the book is based on the recursive descent algorithm.
I like it, it&amp;rsquo;s simple and effective and works reliably.&lt;/p&gt;
&lt;p&gt;However, it is again done in the Java style, mutating private things in the Parser class.
I don&amp;rsquo;t like it, it&amp;rsquo;s error-prone and hard to track what&amp;rsquo;s happening.&lt;/p&gt;
&lt;p&gt;Instead, I made it functional and pure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Parse a sequence of `Token`s into a sequence of expressions.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exprs&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expression&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exprs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;exprs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ExceptionInfo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log/errorf&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[%s:%s] %s at &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each rule then simply returns the expression object, and the next &lt;code&gt;n&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;consume&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(#{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-info&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-info&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Unfinished expression&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                             &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;equality&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comparison&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eof&lt;/span&gt;) (#{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bang_equal&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:equal_equal&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;previous&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;right &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comparison&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tokens&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;Binary&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;])))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, this involves passing n around, but if the function API is consistent, all is well.
All functions in the parser accept a vector of &lt;code&gt;tokens&lt;/code&gt; and the current &lt;code&gt;n&lt;/code&gt; for a position in the array.
No exceptions to that.
Why would you want anything else?&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s so much easier to test too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.parser&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;equality&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 1.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 1]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:plus&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 3]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 1.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 5]} &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; starting from here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:equal_equal&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;==&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 7]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 2.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 10]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eof&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;EOF&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 11]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; 1.0},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:operator&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:equal_equal&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;==&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 7]},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; 2.0}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 5]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.parser&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;equality&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 1.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 1]} &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; starting from here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:plus&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 3]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 1.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 5]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:equal_equal&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;==&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 7]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 2.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 10]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eof&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;EOF&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 11]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; 1.0},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:operator&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:plus&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 3]},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; 1.0}},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:operator&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:equal_equal&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;==&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 7]},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; 2.0}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 5]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Try doing that with a class that mutates &lt;code&gt;current&lt;/code&gt; with every &lt;code&gt;advance&lt;/code&gt; call.&lt;/p&gt;
&lt;h3 id=&#34;polymorphic-dispatch&#34;&gt;Polymorphic dispatch&lt;/h3&gt;
&lt;p&gt;And I must note, that the resulting AST is printed as a sequence of plain maps, each element is actually a class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.parser&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;[{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 1.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 1]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:plus&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 3]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; 1.0, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 5]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eof&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;EOF&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:literal&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; [1 6]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;class&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlox.ast.Binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is important because in Clojure we have two kinds of polymorphic dispatch.
Earlier in this post I&amp;rsquo;ve mentioned protocols, which is a class-based dispatch.
The other one is multimethod-based dispatch, which is a runtime data polymorphism.&lt;/p&gt;
&lt;p&gt;Both allow for creating generic functions, just in a bit different flavor.
For instance, here&amp;rsquo;s how multimethods are often described:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmulti &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] [(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here we have a generic function &lt;code&gt;interact&lt;/code&gt; which expects two arguments, each containing a &lt;code&gt;:type&lt;/code&gt; key, like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ship&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Buran&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asteroid&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; 420000 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unit&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:kg&lt;/span&gt;}})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can define methods for these two to interact:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ship&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s docks %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asteroid&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; {{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unit&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s destroys asteroid of mass %s %s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unit&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asteroid&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ship&lt;/span&gt;] [{{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unit&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;asteroid of mass %s %s pierces the %s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unit&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmethod &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asteroid&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asteroid&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;asteroid of mass %s %s collides with asteroid of mass %s %s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unit&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;other&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:mass&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unit&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means that the &lt;code&gt;interact&lt;/code&gt; function receives two maps, takes a &lt;code&gt;:type&lt;/code&gt; key from each, and forms a tuple &lt;code&gt;[type-a type-b]&lt;/code&gt;.
Then it looks as if it has a definition for said tuple, in our case we&amp;rsquo;ve defined a permutation of methods for &lt;code&gt;:ship&lt;/code&gt; and &lt;code&gt;:asteroid&lt;/code&gt;.
So if we call &lt;code&gt;interact&lt;/code&gt; with our objects, we would see this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Buran&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;destroys&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;asteroid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mass&lt;/span&gt; 420000 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;asteroid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mass&lt;/span&gt; 420000 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kg&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pierces&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Buran&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rock&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;asteroid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mass&lt;/span&gt; 420000 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kg&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collides&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;asteroid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mass&lt;/span&gt; 420000 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It makes sense to use multimethods when dealing with data, and while our AST is data, I choose protocols, because we don&amp;rsquo;t really need to dispatch over a combination of values.
Protocols are also more efficient, as they rely on JVM internal mechanisms for polymorphic dispatch.
Additional reasoning was that at work we don&amp;rsquo;t really use Protocols, so I wanted to try them out in something involved.&lt;/p&gt;
&lt;p&gt;A small downside is that it is a bit harder to represent plain data as AST nodes, as I have to use conversion functions, like &lt;code&gt;-&amp;gt;Binary&lt;/code&gt; that takes a map, and converts it to a record.
But it&amp;rsquo;s better to use Protocols here, so I don&amp;rsquo;t mind some extra preparation steps.
Especially since it really only affects the tests, not the actual code.&lt;/p&gt;
&lt;h2 id=&#34;evaluating-expressions&#34;&gt;Evaluating Expressions&lt;/h2&gt;
&lt;p&gt;And we&amp;rsquo;re back to Protocols vs Visitors.&lt;/p&gt;
&lt;p&gt;The book, once again, uses the Visitor pattern to implement all necessary methods to evaluate our syntax tree as a program.
I won&amp;rsquo;t go and repeat the comparison, instead, here&amp;rsquo;s how I&amp;rsquo;ve done it in CljLox:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; cljlox.evaluator&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defprotocol &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Literal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Grouping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:expression&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;right &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;right &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:minus&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;check-number-op!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bang&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truth?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Unsupported unary operator&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt;})))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The key point here is that Protocols are open, it&amp;rsquo;s possible to extend them from other parts of the system.
It&amp;rsquo;s doable in both ways too - you can extend an existing protocol with a new class, or you can give an existing class a new protocol.
In this project, I use both &lt;code&gt;extend-protocol&lt;/code&gt; and &lt;code&gt;extend-type&lt;/code&gt; to provide all necessary method implementations.&lt;/p&gt;
&lt;h2 id=&#34;statements-and-state&#34;&gt;Statements and State&lt;/h2&gt;
&lt;p&gt;Now we have to deal with the state.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defonce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*env&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; {}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it.&lt;/p&gt;
&lt;h2 id=&#34;control-flow&#34;&gt;Control Flow&lt;/h2&gt;
&lt;p&gt;Implementing control flow is an interesting…&lt;/p&gt;
&lt;p&gt;Just kidding, let&amp;rsquo;s talk about state.&lt;/p&gt;
&lt;h2 id=&#34;statements-and-state&#34;&gt;Statements and State&lt;/h2&gt;
&lt;p&gt;So, state.
Yes, I&amp;rsquo;m using an &lt;code&gt;atom&lt;/code&gt; here to hold the state of the interpreter.
Probably I could have used a &lt;code&gt;volatile&lt;/code&gt; instead, but I chose &lt;code&gt;atom&lt;/code&gt; for some reason.
There are no threads in CljLox, at least not yet, so &lt;code&gt;volatile&lt;/code&gt; would work just as fine.
Later I switched to &lt;code&gt;volatile&lt;/code&gt;, though.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve changed/created the &lt;code&gt;evaluate&lt;/code&gt; method for &lt;code&gt;Var&lt;/code&gt;, &lt;code&gt;Variable&lt;/code&gt; and &lt;code&gt;Assign&lt;/code&gt; nodes of the Ast:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Var&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*env&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*env&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::not-found&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= val &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::not-found&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Undefined variable &amp;#39;%s&amp;#39;.&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Assign&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;contains? &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*env&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*env&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Undefined variable &amp;#39;%s&amp;#39;.&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This, however, only handles the global state, so I later had to change it to this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-env&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parent&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:enclosing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; {}})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defonce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*global-env&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-env&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-variable&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Var&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;initializer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-variable&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; @&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;contains? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enclosing&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:enclosing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enclosing&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Undefined variable &amp;#39;%s&amp;#39;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;})))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-variable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Assign&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;contains? &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Undefined variable &amp;#39;%s&amp;#39;.&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Block&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;statements&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;&amp;#39; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doseq &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;statement&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;statements&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;statement&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;&amp;#39;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a lot of code to read, so I&amp;rsquo;ll outline the changes.&lt;/p&gt;
&lt;p&gt;First, now the &lt;code&gt;evaluate&lt;/code&gt; method accepts two arguments, instead of just one.
Yes, we&amp;rsquo;re now passing the environment around.
In a non-functional interpreter, we could just set the current environment of the &lt;code&gt;Evaluator&lt;/code&gt; class, once we introduce new or leave a scope but here we can&amp;rsquo;t do that.
Err, we &lt;em&gt;can&lt;/em&gt;, I just chose not to, because again - it is much easier to reason about the code.
The environment is just a map wrapped into an atom, after all.&lt;/p&gt;
&lt;h2 id=&#34;control-flow&#34;&gt;Control Flow&lt;/h2&gt;
&lt;p&gt;Aside from adding a few new extensions to the protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;If&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;else&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;test &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truth?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Logical&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;left &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;right&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;left &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;left &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;operator&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:or&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truth?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;right &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:and&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truth?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;left&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;right &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;we also implement loops in this section.
While I like the approach of implementing &lt;code&gt;while&lt;/code&gt; in the host language, and &lt;code&gt;for&lt;/code&gt; terms of our definition of &lt;code&gt;while&lt;/code&gt;, honestly, I would prefer a tour about tail call elimination instead.
It would probably make things more complicated, but I feel that it would bring more value to the table.
Since this book teaches how to create a language, I think it is worth mentioning the tail call recursion approach at the very least.&lt;/p&gt;
&lt;p&gt;When I was programming in C and had no idea an infinite recursion was even possible, learning that there are some languages that can do that was a huge revelation.
How many algorithms could I have written in far less complicated ways, by using the continuation passing style?
Yeah, a weird statement to make, but CSP can be easier to understand at times.&lt;/p&gt;
&lt;h2 id=&#34;functions&#34;&gt;Functions&lt;/h2&gt;
&lt;p&gt;Now we&amp;rsquo;re getting into the meat of the interpreter.
We can put together all our variables, scopes, and loops, and wrap them into something we can define and call later.
Everything starts with a different protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defprotocol &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ICallable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arguments&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And later we can extend it with new types:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;LoxCallable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ICallable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arity&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arguments&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arity&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arguments&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arguments&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Expected %s arguments but got %s.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arity&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arguments&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;}))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-protocol&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ICallable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can only call functions and classes.&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;runtime-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Can only call functions and classes.&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, I really like this feature of Clojure - defining a new protocol and extending it with already existing types like &lt;code&gt;Object&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;, is great.
Same thing with already existing types, such as &lt;code&gt;LoxCallable&lt;/code&gt; (used for native interpreter&amp;rsquo;s functions) - we can just give it a new protocol and implement it.
No need for visitors, you just do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;extend-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IInterpretable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;LoxFunction.&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-in&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defrecord &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;LoxFunction&lt;/span&gt; [^&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;declaration&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closure&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ICallable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call&lt;/span&gt; [{{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;params&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;]} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:declaration&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closure&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doseq &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arg&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map vector &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;params&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-in&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arg&lt;/span&gt;))] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;evaluate&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ExceptionInfo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:return&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IStringable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tostring&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;function: %s&amp;gt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:declaration&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lexeme&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every time I read things like &lt;code&gt;visitFunctionStmt&lt;/code&gt; I question myself - what exactly visiting does do, why does it create an object, and so on?
Well, I&amp;rsquo;m not a Java programmer for a reason, I guess, visitors, abstract fabrics, and other such things don&amp;rsquo;t tickle my fancy.&lt;/p&gt;
&lt;h2 id=&#34;resolving-and-binding&#34;&gt;Resolving and Binding&lt;/h2&gt;
&lt;p&gt;I know, I&amp;rsquo;m being a bit shallow on details, but honestly, I just don&amp;rsquo;t remember well what was going on in my mind back then.
The resolver, however, is another thing that I took the liberty to make immutable, so it&amp;rsquo;s quite different from the book.
I have a &lt;a href=&#34;https://gitlab.com/andreyorst/cljlox/-/commit/e25dbca7d814bdbc71e93f9869a21992687ca7ee&#34; target=&#34;_blank&#34;&gt;giant commit&lt;/a&gt; where I basically change this in every protocol method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (defprotocol ICallable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-  (call [self arguments token env]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+  (call [self arguments token env locals]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, why would I do that?
No reason, really.
I just noticed that the only place I change locals is in the evaluation entry point and each new scope.
However, none of these have to use the mutable state, as it is purely for convenience (and the style the book is written in), so I changed it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(defn run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([source]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (run source nil))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([source file]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (let [fmt (if file (str file &#34; %s&#34;) &#34;%s&#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         {:keys [errors tokens]} (tokenize source)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (if (seq errors)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (with-out-err
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (doseq [error errors]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (println (format fmt (str error)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-       (let [expressions (parse tokens)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-         (reset! *locals {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-         (doseq [expr expressions]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-           (lox-resolve expr []))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+       (let [expressions (parse tokens)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+             locals (reduce (fn [locals expr]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                              (merge locals (second (lox-resolve expr [[] {}]))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                            {} expressions)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (reduce (fn [_ expr]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (when (seq expr)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-                     (interpret expr)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+                     (interpret expr locals)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  nil expressions))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A similar change was needed in the &lt;code&gt;resolve-local&lt;/code&gt; function, as now it would use an additional storage passed in as an argument:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-(defn- resolve-local [expr name scope-stack]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+(defn- resolve-local [expr name [scope-stack locals]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (when (seq scope-stack)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (loop [i (dec (count scope-stack))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (if (contains? (get scope-stack i) (:lexeme name))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        (register-expr-scope expr (- (count scope-stack) 1 i))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-        (when (&amp;gt; i 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-removed&#34;&gt;-          (recur (dec i)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+        [scope-stack (assoc locals expr (- (count scope-stack) 1 i))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+        (if (&amp;gt; i 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+          (recur (dec i))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span class=&#34;diff-added&#34;&gt;+          [scope-stack locals])))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the rest of the changes the resolver is fully immutable, but is it worth the effort?
Well, kinda - it is much easier to debug, and I was able to walk the code, looking at when the locals appeared in the storage much easier.
I could, theoretically, make the same change for the global scope storage, but that would be way too much work, and I was tired of this change already.
That would help to deal with the annoyance that the scope storage refers to itself at some point, making the debugger unhappy and cycling infinitely during result inspection.&lt;/p&gt;
&lt;p&gt;And yes, &lt;a href=&#34;https://gitlab.com/andreyorst/cljlox/-/commit/92430e8048ad1c1f4151f6e22c61be666815addf&#34; target=&#34;_blank&#34;&gt;later&lt;/a&gt; I had to store locals in the &lt;code&gt;volatile!&lt;/code&gt; storage to keep them in the REPL, but not because it is mandatory, I was just lazy to put it into the loop.&lt;/p&gt;
&lt;h2 id=&#34;classes&#34;&gt;Classes&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re entering the part of the book I don&amp;rsquo;t like, yay!
As you know, I like Clojure, but not really because it is a Lisp.
I like Clojure because it is a functional language without a type system burden.&lt;/p&gt;
&lt;p&gt;If I were into functional programming &lt;strong&gt;and&lt;/strong&gt; into type systems, I would be probably writing about Haskell or Idris, but I&amp;rsquo;m writing about Clojure, and more often Lua/Fennel.
If I were into Lisp &lt;strong&gt;and&lt;/strong&gt; LISP, I would probably be writing about Common Lisp &lt;em&gt;or&lt;/em&gt; Scheme.
But I&amp;rsquo;m into type-less, functional approach so Clojure is a perfect fit for me.
Well, maybe Elixir as well, but they&amp;rsquo;re bringing a type system in, so I guess they&amp;rsquo;re off track on what makes the language fun.
But I digress.&lt;/p&gt;
&lt;p&gt;Out of all the features I dislike the most are classes and inheritance, and these are the final chapters of the first half of the book.
I dislike classes and inheritance mainly because they are only complicated things in my past experience.
I worked on a somewhat large code base in C++ before, and inheritance was a huge pain there.&lt;/p&gt;
&lt;p&gt;Other languages that feature classes often over-complicate things as well - look at Java with its visitors, factories, and such.
So I tend to dislike classes.
To be fair, there are use cases for this paradigm, and there are fine implementations like CLOS or Smalltalk, but I would not try to base everything on classes.&lt;/p&gt;
&lt;p&gt;Speaking of this book - why are we already at classes when we didn&amp;rsquo;t cover any base data structures?
There are strings, yes, but where are arrays and records/hash-maps?
What about tuples?
Some could argue that strings &lt;em&gt;can&lt;/em&gt; be used for arrays or their code could be repurposed, but not in our case, as we&amp;rsquo;re using the host platform&amp;rsquo;s strings which are immutable.
Implementing strings as byte arrays is a thing, but it&amp;rsquo;s not what the book did, so there are simply no arrays in Lox.&lt;/p&gt;
&lt;p&gt;Well, we can implement a linked list with classes, but there&amp;rsquo;s literally no way to implement an array without explicit access to the memory.
I don&amp;rsquo;t really want to cover the changes in the code base, as there&amp;rsquo;s nothing you haven&amp;rsquo;t seen before in this post.&lt;/p&gt;
&lt;p&gt;One thing I do want to cover though is the use of classes to implement namespaces.
This is covered in the &amp;ldquo;Challenges&amp;rdquo; section after the actual chapter:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have methods on instances, but there is no way to define “static” methods that can be called directly on the class object itself. Add support for them. Use a class keyword preceding the method to indicate a static method that hangs off the class object.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;Math&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; square(n) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; n * n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;Math&lt;/span&gt;.square(3); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Prints &amp;#34;9&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can solve this however you like, but the “metaclasses” used by Smalltalk and Ruby are a particularly elegant approach. Hint: Make LoxClass extend LoxInstance and go from there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Saying I dislike this approach is to not say anything.
Why would you do that?
It&amp;rsquo;s like stating: &amp;ldquo;Our language can&amp;rsquo;t do namespaces but do not worry, we have static methods that provide exactly the same thing, you just do it the ugly way&amp;rdquo;.
Well, it probably makes sense in some languages like Smalltalk, but not everything is Smalltalk.&lt;/p&gt;
&lt;p&gt;Take a look at Lua for a second.
It doesn&amp;rsquo;t have namespaces.
It doesn&amp;rsquo;t have classes either.
Yet, it does have a way of defining modules - it just uses hash tables for that.
And it does the same thing with classes - you use a hash table for that.
You don&amp;rsquo;t have to be Clojure to just use maps!&lt;/p&gt;
&lt;p&gt;Then the book proceeds:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Most modern languages support “getters” and “setters”—members on a class that look like field reads and writes but that actually execute user-defined code. Extend Lox to support getter methods. These are declared without a parameter list. The body of the getter is executed when a property with that name is accessed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every time I see this, I ask myself &amp;ldquo;Why?!&amp;rdquo; - a pointless question.&lt;/p&gt;
&lt;p&gt;Look at this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; Circle {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  init(radius) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.radius = radius;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  area {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 3.141592653 * &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.radius * &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.radius;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; circle = Circle(4);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print circle.area; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// Prints roughly &amp;#34;50.2655&amp;#34;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Accessing the &lt;code&gt;area&lt;/code&gt; &lt;em&gt;field&lt;/em&gt; we get the area of a circle with the radius of &lt;code&gt;4&lt;/code&gt; units.
Cool, right?&lt;/p&gt;
&lt;p&gt;Now look at this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; Circle {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  init(radius) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;this&lt;/span&gt;.radius = radius;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  area {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;while&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; circle = Circle(4);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print circle.area; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// good luck debugging this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Surely, looking at the &lt;code&gt;circle.area&lt;/code&gt; part of the code you can&amp;rsquo;t see that there&amp;rsquo;s a call there.
That&amp;rsquo;s why we have syntax, mind you!
This &amp;ldquo;feature&amp;rdquo; to me looks like a deliberate shot to the foot - the expression power it gives you is equal to not hitting two keys on the keyboard yet you introduce ambiguity to your language.&lt;/p&gt;
&lt;p&gt;It was at this point where I stopped even trying to do any of the so-called &amp;ldquo;Challenges&amp;rdquo;, but I will have to talk about them later, as I do have more things to say.&lt;/p&gt;
&lt;h2 id=&#34;inheritance&#34;&gt;Inheritance&lt;/h2&gt;
&lt;p&gt;Most of the changes in this section are sorely related to how we access methods, fields, and so on, so again, I won&amp;rsquo;t go into actual code differences.
Call me lazy.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m glad that the book went for a single inheritance approach though, as nothing gives me a stronger desire to punch someone than seeing a class that inherits from another 16, each of which also inherits from more than three.
I have seen this in the C++ codebase I mentioned before.
Looking up where the method is defined is hard enough, and this was a C++ written before things like language servers were a thing, so tags were the only way to navigate it in a somewhat intelligent way.
Unfortunately, generating tags was slow, and I had to update them frequently, as I made the changes to the code.
Often, the jump wasn&amp;rsquo;t possible because tags were outdated.&lt;/p&gt;
&lt;p&gt;So, having a single inheritance is, perhaps, limiting as you can&amp;rsquo;t go nuts and say that &lt;code&gt;Cat&lt;/code&gt; inherits from both &lt;code&gt;Animal&lt;/code&gt; and &lt;code&gt;Carnivore&lt;/code&gt;, which may be a bummer, I guess, but this is a textbook example, I have yet to see OOP code like that.
Personally, I&amp;rsquo;ll take single inheritance over multiple inheritance any time.
But I&amp;rsquo;d rather do no inheritance at all, to be honest, protocols are much more fun to use.&lt;/p&gt;
&lt;h2 id=&#34;final-thoughts&#34;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;This post is a total trainwreck.
I should have published it in the middle of April 2022 but for some reason, I didn&amp;rsquo;t.
To be fair, I still have a draft of the first version of this post, and it is horrible, so I guess it&amp;rsquo;s good that I didn&amp;rsquo;t publish it before.
Such posts should be written during the time you spend with the book, not afterward, and especially not after almost two years.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s why I&amp;rsquo;ll be re-writing the second half of the book in &lt;a href=&#34;https://ziglang.org/&#34; target=&#34;_blank&#34;&gt;Zig&lt;/a&gt; and capturing my thoughts as I go through it!
For the &lt;strong&gt;second time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Yes, I already tried this approach, but given that I didn&amp;rsquo;t know Zig at all back then the resulting code is terrible.
Can&amp;rsquo;t say I&amp;rsquo;m proud about the Clojure version either, but the Zig version is heaps and bounds worse in all areas.
Hopefully, this time around I will be able to do a better job.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve mentioned that I have more things to say about the &amp;ldquo;Challenges&amp;rdquo;, waiting for the reader at each chapter&amp;rsquo;s end.
I guess, this will have to wait for the second post, which I&amp;rsquo;m sure won&amp;rsquo;t take years to appear.
Ahem.&lt;/p&gt;
&lt;p&gt;You see, most of the challenges, or should I say, exercises were not really out of the way in the first half of the book.
Can&amp;rsquo;t say so for the second half though - I had major issues going through the book because I completed the challenges.
This wasn&amp;rsquo;t an issue for the first book because most challenges are easy, but this can&amp;rsquo;t be said for the second half, as we&amp;rsquo;re no longer in the managed territory.
Implementing your bytecode interpreter is much harder than using your host language for the heavy lifting.&lt;/p&gt;
&lt;p&gt;Anyway, I hope you found this post interesting enough to read til here.
If not, well, that&amp;rsquo;s fair, I didn&amp;rsquo;t find it interesting to read too, honestly.
But I had to get it out of my system, and hopefully, the second part will be more refined.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Thoughts on Crafting Interpreters - Part 1&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 03 Dec 2023 21:35:00 +0300</pubDate>
    </item><item>
      <title>Linux Music Players</title>
      <link>https://andreyor.st/posts/2023-11-19-linux-music-players/</link>
      <guid>https://andreyor.st/posts/2023-11-19-linux-music-players/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m feeling ranty this week for some reason.
Today will be no different and I&amp;rsquo;ll post another rant on the software world but not about programming.
Instead, I want to tip into the consumer application world, and shit on the current state of music players on GNU/Linux specifically, although the situation is as bad as on other platforms IMO.&lt;/p&gt;
&lt;p&gt;Not long ago I bought a new set of headphones and decided to upgrade my listening experience a bit.
For the last few years, I usually listened to music on my phone via some streaming service - I&amp;rsquo;ve tried plenty and wasn&amp;rsquo;t really satisfied with any of these, although there are some good things each does.
For example, thanks to Spotify and Google Play Music before it, I&amp;rsquo;ve discovered a lot of artists that I wouldn&amp;rsquo;t likely hit if not for their algorithm.
Another thing - listening to music via a subscription service is dirt cheap.&lt;/p&gt;
&lt;p&gt;My listening routine can be described as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pick an album;&lt;/li&gt;
&lt;li&gt;Hit play;&lt;/li&gt;
&lt;li&gt;Enjoy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Yes, I&amp;rsquo;m not into playlists, especially not into various methods for organizing music based on mood, algorithmically, by genre, etc.
In fact, I openly despise playlists.
I hate when players shuffle my music (looking at you, Spotify), so all I really need from a music player is to act mainly like a CD player/Vinyl turntable.
I load a specific album, listen to it, and I&amp;rsquo;m done with it.
An album is a piece of art - shuffling songs is like shuffling episodes of a show or chapters in a book.&lt;/p&gt;
&lt;p&gt;What I did like in Spotify, and Google Play Music before it, was discovering new music.
The subscription model means that I can listen to all new releases whenever they come out without having to pay for each of them, purchasing only those I absolutely want to keep, but on some other service that allows me to download the actual files, and listen to them without connecting to internet on any of my devices and in any music player.
For those wondering, you can save your music on Spotify for later listening, but you can&amp;rsquo;t use Spotify without an internet connection even for listening to your downloaded music, because Spotify needs to check if your subscription is still active.
And you can&amp;rsquo;t extract music from Spotify, legally, at least, so if Spotify disappears, all your purchased music goes down with it.
I often find myself in this situation when I&amp;rsquo;m on a train, kilometers away from any cellular network, and Spotify refuses to load my offline music because there&amp;rsquo;s &amp;ldquo;no internet&amp;rdquo;.
So I prefer to keep music I really enjoy out of streaming services.&lt;/p&gt;
&lt;p&gt;Discovering new music on a snap is great, and the subscription model works for that especially well, but one of the problems with most subscription services is audio quality.
When I&amp;rsquo;m listening on my phone I usually don&amp;rsquo;t care - it doesn&amp;rsquo;t feature a great DAC, I&amp;rsquo;m listening through wireless IEMs, although of decent quality, this still limits the quality of sound to what Bluetooth protocol is available for my phone.
And another important thing with music on the phone - I&amp;rsquo;m listening to it on the go, so there&amp;rsquo;s little time to concentrate on details, like when I do at home when I have time to just listen to music without any distractions.
So before you suggest using something like Tidal instead of Spotify just to get the quality audio - I don&amp;rsquo;t really need this kind of audio fidelity on the go, and at home, I have my FLACs.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s go back to the main topic - you got your FLACs, how to listen to them on your PC?
Well, you use an audio player, of course, but which one?&lt;/p&gt;
&lt;p&gt;My operating system of choice is Fedora and there are plenty of audio players for Linux that I can try.
For the past few years, I&amp;rsquo;ve been using MVP as my music player - it can play everything I need, it stays out of the way, and it is fast and resource-friendly.
But it is extremely cumbersome to use.
While not a problem for me, as I rarely listened to music on my PC previously, now that I have a good pair of headphones, I tend to do it more often.
And user experience with MPV started to show.
My main problems with MPV are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s a video player primarily so its UI is oriented towards the video playback.&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t click on the song in the album and play it, the song list only appears when you switch tracks as a visual aid.&lt;/li&gt;
&lt;li&gt;It plays everything in the given directory, even cover images.
&lt;ul&gt;
&lt;li&gt;If you have a &lt;code&gt;.cue&lt;/code&gt; file along with the album file, MPV will first play the &lt;code&gt;.cue&lt;/code&gt; file, then it will play the album file, doubling the total length.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s no notion of a music library besides your filesystem - you just drag and drop files to the player.&lt;/li&gt;
&lt;li&gt;It doesn&amp;rsquo;t remember where I was if you close it.&lt;/li&gt;
&lt;li&gt;Wayland support is not great, for a quite long time the drag-and-drop feature did not work on GNOME at all for the flatpak package.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But these are the problems with stock MPV, there are plenty of other frontends for it, that may work better.
I haven&amp;rsquo;t tried these, and maybe I will in the future.
&lt;a href=&#34;http://ovoplayer.altervista.org/&#34; target=&#34;_blank&#34;&gt;Ovoplayer&lt;/a&gt; looks promising, but sadly doesn&amp;rsquo;t have a package for Fedora, and for some reason doesn&amp;rsquo;t start from an Ubuntu container.&lt;/p&gt;
&lt;p&gt;But this won&amp;rsquo;t be a rant if I&amp;rsquo;m going to list good players, so let&amp;rsquo;s start with &amp;ldquo;first-party&amp;rdquo; players, provided with the desktop environment.
After that, let&amp;rsquo;s look at some &lt;em&gt;modern&lt;/em&gt; players.
Then, I&amp;rsquo;ll list some other commonly suggested players.&lt;/p&gt;
&lt;h3 id=&#34;gnome-music&#34;&gt;&lt;a href=&#34;https://apps.gnome.org/Music/&#34; target=&#34;_blank&#34;&gt;GNOME Music&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As I&amp;rsquo;m using GNOME let&amp;rsquo;s start with the GNOME Music.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/gnome-music.png&#34;
         alt=&#34;Figure 1: GNOME Music screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;GNOME Music screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;First things first, I used this player years ago and I remember it being OK.
However, trying it today I can&amp;rsquo;t say that I like it.
Well, can&amp;rsquo;t say I dislike it either, it just doesn&amp;rsquo;t work for me.&lt;/p&gt;
&lt;p&gt;It has a nice UI, though I&amp;rsquo;d prefer a slimmer one.
Importantly, it has dedicated tabs for albums, artists, individual song lists, and a separate tab for playlists.
Unfortunately, GNOME Music doesn&amp;rsquo;t support &lt;code&gt;.cue&lt;/code&gt; sheets.
I have some releases that are using &lt;code&gt;.cue&lt;/code&gt; sheets and I, personally, don&amp;rsquo;t want to go through the hassle of extracting individual tracks.
As a result, these releases are missing from the Albums tab.
There&amp;rsquo;s an open &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gnome-music/-/issues/57&#34; target=&#34;_blank&#34;&gt;bug report&lt;/a&gt; asking for the &lt;code&gt;.cue&lt;/code&gt; support that dates back to 2016.&lt;/p&gt;
&lt;p&gt;These albums show up in the &amp;ldquo;Songs&amp;rdquo; section though, so you can listen to them, as a single stream.
That&amp;rsquo;s not bad, considering that I&amp;rsquo;m usually listening to albums from start to finish, but what&amp;rsquo;s the point of having an organized albums section if it doesn&amp;rsquo;t show all of the albums, and you have to remember that you still have them in the tracks section.
That can contain thousands of items because of the size of the music library.&lt;/p&gt;
&lt;p&gt;Oh, and you can&amp;rsquo;t change your music folder, it only works with &lt;code&gt;~/Music&lt;/code&gt; for some reason.
Well, I, personally, don&amp;rsquo;t have a problem with that - that&amp;rsquo;s where I store music on my PC, but it may not work for other people.&lt;/p&gt;
&lt;h3 id=&#34;amberol&#34;&gt;&lt;a href=&#34;https://apps.gnome.org/en/Amberol/&#34; target=&#34;_blank&#34;&gt;Amberol&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;GNOME had a neat idea - create a list of applications designed specifically for GNOME with its guidelines in mind.
It is called &lt;a href=&#34;https://apps.gnome.org/&#34; target=&#34;_blank&#34;&gt;GNOME Circle&lt;/a&gt;, and it is listed among GNOME&amp;rsquo;s core apps.
The Amberol, at the moment of writing, is one of the first apps on the list, and it is a music player.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/amberol-full.png&#34;
         alt=&#34;Figure 2: Amberol screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Amberol screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Similarly to GNOME Music, Amberol doesn&amp;rsquo;t support &lt;code&gt;.cue&lt;/code&gt; sheets.
Again, there&amp;rsquo;s a &lt;a href=&#34;https://gitlab.gnome.org/World/amberol/-/issues/177&#34; target=&#34;_blank&#34;&gt;bug report&lt;/a&gt; for that, but the reason it doesn&amp;rsquo;t support &lt;code&gt;.cue&lt;/code&gt; is due to the method they access files.
Sandboxing, which is used by flatpaks causes problems, as the portal interface isn&amp;rsquo;t designed for this particular use-case.&lt;/p&gt;
&lt;p&gt;Unlike GNOME Music, however, Amberol doesn&amp;rsquo;t show these albums in the playlist at all.
Don&amp;rsquo;t ask me why, I don&amp;rsquo;t know.
And unlike GNOME Music, there is no dedicated tab for albums, artists, or anything really - only a single playlist, consisting of all tracks in your music library.
I know that Amberol tries to be a simple music player, but I wouldn&amp;rsquo;t say that GNOME Music was complicated.
Going simpler than GNOME Music is hurting usability.&lt;/p&gt;
&lt;h3 id=&#34;lollypop&#34;&gt;&lt;a href=&#34;https://wiki.gnome.org/Apps/Lollypop&#34; target=&#34;_blank&#34;&gt;Lollypop&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another music player that is made using GNOME guidelines.
It has more features than Amberol, and maybe even more features than GNOME Music:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/lollypop.png&#34;
         alt=&#34;Figure 3: Lollypop screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Lollypop screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;But once again - missing albums due to missing &lt;code&gt;.cue&lt;/code&gt; support.
Are you for real?
Another &lt;a href=&#34;https://gitlab.gnome.org/World/lollypop/-/issues/257&#34; target=&#34;_blank&#34;&gt;8-year-old bug report&lt;/a&gt; asking for &lt;code&gt;.cue&lt;/code&gt; support with no resolution.
Well, at least there is some discussion going on, so the ticket isn&amp;rsquo;t entirely stale.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s even weirder, it seems that Lollypop doesn&amp;rsquo;t have a tracklist, unlike the previous two players.
It&amp;rsquo;s weird because while I don&amp;rsquo;t use this feature, it&amp;rsquo;s so fundamental to all music players we&amp;rsquo;re going to discuss further, not having it is just strange.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m starting to think that the GNOME project simply can&amp;rsquo;t have a decent music player.
Let&amp;rsquo;s look at how KDE does this.&lt;/p&gt;
&lt;h3 id=&#34;elisa&#34;&gt;&lt;a href=&#34;https://apps.kde.org/elisa/&#34; target=&#34;_blank&#34;&gt;Elisa&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A few years ago I was using KDE for a brief period, but I can&amp;rsquo;t remember if KDE did have their dedicated music player back then.
Or maybe I wasn&amp;rsquo;t bothered to check, as I already used MPV.
As far as I can see today the KDE Project has the Elisa music player:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/elisa.png&#34;
         alt=&#34;Figure 4: Elisa screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;Elisa screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Well, I tried it, and&amp;hellip; missing albums, &lt;strong&gt;again&lt;/strong&gt;!
And again due to the lack of &lt;code&gt;.cue&lt;/code&gt; support!
&lt;a href=&#34;https://bugs.kde.org/show_bug.cgi?id=398694&#34; target=&#34;_blank&#34;&gt;There&amp;rsquo;s a bug report for that again&lt;/a&gt;, and there are even some duplicates, probably because their bug tracker web interface is abysmal.&lt;/p&gt;
&lt;p&gt;Seriously, are &lt;code&gt;.cue&lt;/code&gt; sheets that rare?
Maybe they are hard to implement properly?
Up to this moment, only MPV could deal with them with no problem, and it&amp;rsquo;s a shame.&lt;/p&gt;
&lt;p&gt;Well, at least these &lt;code&gt;.cue&lt;/code&gt; albums show up in the Tracks section, as a single track.
Hitting play on one of them, however, plays a random album instead.
Welp.
It&amp;rsquo;s a shame though, the UI is clean, everything is mostly logically displayed, and there&amp;rsquo;s little wasted space, unlike in many GNOME apps.&lt;/p&gt;
&lt;h3 id=&#34;amarok&#34;&gt;&lt;a href=&#34;https://apps.kde.org/amarok/&#34; target=&#34;_blank&#34;&gt;Amarok&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another project is often seen on KDE systems.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/amarok.png&#34;
         alt=&#34;Figure 5: Amarok screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;Amarok screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;No Flathub entry, that&amp;rsquo;s a good start.
You see, I mostly install software through flatpaks because I use Fedora Silverblue - an immutable OS.
This can cause problems, and I know that, but most of the time everything works fine.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/clementine.png&#34;
         alt=&#34;Figure 6: Don&amp;amp;rsquo;t worry, Clementine, I&amp;amp;rsquo;ll get to you soon&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;Don&amp;rsquo;t worry, Clementine, I&amp;rsquo;ll get to you soon&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Once again, missing &lt;code&gt;.cue&lt;/code&gt; support.
Which is weird, as there are reports on the internet that Amarok does support &lt;code&gt;.cue&lt;/code&gt; since version 1.2.4.
Maybe it was lost along the way, I don&amp;rsquo;t know.
Well, at least it shows the albums in the list of all media, albeit as a single file.
Thank you for not omitting these, at least.
And it actually plays them, unlike Elisa.&lt;/p&gt;
&lt;p&gt;The user interface, on the other hand, is weird.
I couldn&amp;rsquo;t figure out if I&amp;rsquo;d pressed the pause button, as it doesn&amp;rsquo;t change shape, and the visualizer doesn&amp;rsquo;t stop immediately either.
This is because there&amp;rsquo;s by default a two-second fade-out that has to play out before the track is put on pause, and the button doesn&amp;rsquo;t change until the track is fully stopped.
I dislike fadeouts, crossfades, and other things like that, sorry.&lt;/p&gt;
&lt;p&gt;Well, it&amp;rsquo;s an old project, and its UI is a product of its time, I guess.&lt;/p&gt;
&lt;h3 id=&#34;rhythmbox&#34;&gt;&lt;a href=&#34;https://wiki.gnome.org/Apps/Rhythmbox&#34; target=&#34;_blank&#34;&gt;Rhythmbox&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/rhythmbox.png&#34;
         alt=&#34;Figure 7: Rhythmbox screenshot from Flathub&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 7: &lt;/span&gt;Rhythmbox screenshot from Flathub&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Another fairly old music player.
Yet, the user interface is clean, uncluttered, and concise.
Nothing but praise from me on the UI.&lt;/p&gt;
&lt;p&gt;Again, &lt;strong&gt;no &lt;code&gt;.cue&lt;/code&gt; support&lt;/strong&gt;!
&lt;strong&gt;WHY?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, at least, there&amp;rsquo;s a plugin.
The flatpak version couldn&amp;rsquo;t see external plugins, so I had to install it as an rpm package inside a container (Silberblue works like that).
And while it works now, for some reason, the &lt;code&gt;.cue&lt;/code&gt; albums aren&amp;rsquo;t shown in the albums section.
Instead, they&amp;rsquo;re shown under the Unknown section, and clicking on such an album opens a separate window with track listing obtained from the &lt;code&gt;.cue&lt;/code&gt; file.
So the experience isn&amp;rsquo;t great, unfortunately.
But we&amp;rsquo;re close.&lt;/p&gt;
&lt;h3 id=&#34;strawberry&#34;&gt;&lt;del&gt;Clementine&lt;/del&gt; &lt;a href=&#34;https://www.strawberrymusicplayer.org/&#34; target=&#34;_blank&#34;&gt;Strawberry&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I told you that we&amp;rsquo;re going to talk about Clementine.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/strawberry.png&#34;
         alt=&#34;Figure 8: Strawberry screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 8: &lt;/span&gt;Strawberry screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Strawberry is a fork of Clementine, which is a fork of Amarok.
Same as Amarok, the default UI is horrible, sorry.
But, &lt;strong&gt;finally&lt;/strong&gt;, a &lt;code&gt;.cue&lt;/code&gt; support!
Which makes it even stranger, as Amarok itself did not work with &lt;code&gt;.cue&lt;/code&gt; files.
Maybe I&amp;rsquo;m missing something?&lt;/p&gt;
&lt;p&gt;Importing my music library I can now see all of the albums, and play individual tracks, but it&amp;rsquo;s so &lt;em&gt;clumsy&lt;/em&gt;.
When I open the album, and double click on the track, this only track is appended to the playlist.
And it isn&amp;rsquo;t the one played either.&lt;/p&gt;
&lt;p&gt;I do hate playlists, but what I hate even more is play queues, and this action acts like adding to a queue.
I don&amp;rsquo;t want to deal with a queue at all - give me an album list, play the one I&amp;rsquo;m interested in, or start from a track I&amp;rsquo;m interested in going forward.
&lt;strong&gt;Simple as that.&lt;/strong&gt;
In Strawberry, I have to clear a playlist, replace the playlist with an album playlist, or create a new playlist, and it&amp;rsquo;s just tiresome when all I want is to listen to a specific album.&lt;/p&gt;
&lt;p&gt;Why is it so hard for most players today?
Don&amp;rsquo;t tell me I&amp;rsquo;m using players wrong.
I mean, I &lt;em&gt;can&lt;/em&gt; get this from Strawberry, just going through several hoops.
Well, we were going into older players, let&amp;rsquo;s look at something more recent then.
Maybe some modern players took inspiration from Spotify and others and made something similar.&lt;/p&gt;
&lt;h3 id=&#34;tambourine&#34;&gt;&lt;a href=&#34;https://github.com/MMarco94/tambourine-music-player/&#34; target=&#34;_blank&#34;&gt;Tambourine&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Well, I&amp;rsquo;ve kinda covered modern players already at the start of this post, but these were desktop environment-specific players.
Mostly.
This one is just an independent project.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/tambourine.png&#34;
         alt=&#34;Figure 9: Tambourine screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 9: &lt;/span&gt;Tambourine screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The interface is laggy and we&amp;rsquo;re back to no &lt;code&gt;.cue&lt;/code&gt; support.
It has potential, though.&lt;/p&gt;
&lt;p&gt;Also, good luck searching for a &amp;ldquo;Tambourine music player&amp;rdquo;.&lt;/p&gt;
&lt;h3 id=&#34;nuclear&#34;&gt;&lt;a href=&#34;https://nuclear.js.org/&#34; target=&#34;_blank&#34;&gt;Nuclear&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve seen this player being praised online several times but never took a look.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/nuclear.png&#34;
         alt=&#34;Figure 10: Nuclear screenshot from the project repository&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 10: &lt;/span&gt;Nuclear screenshot from the project repository&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The startup time of several seconds and crashed when I tried to import my music library.
It&amp;rsquo;s funny, though, this is what they say on their web page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Say goodbye to proprietary music players filled with ads, tracking, and profiling.
Nuclear empowers you to listen to what you want, where you want, and how you want, for free&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They say it like there are no other non-proprietary music players without all of that.
Well, maybe, if we&amp;rsquo;re talking about service-based players, like Spotify, but I&amp;rsquo;m here for a local-first player.
Their user interface is filled with some online garbage, trending artists, and such, not sure what service it comes from.
The local library is waaay below in the list, and, as mentioned, it doesn&amp;rsquo;t work.
I&amp;rsquo;ve limited it to a portion of the library, and there is no &lt;code&gt;.cue&lt;/code&gt; support, once again.&lt;/p&gt;
&lt;p&gt;But again, it&amp;rsquo;s funny, when I pressed play on the album, the player immediately added something that wasn&amp;rsquo;t in my library to the queue right after it.
Kinda disagrees with the statement they make on the web page.
That&amp;rsquo;s not &lt;em&gt;how I want&lt;/em&gt; to listen to music.&lt;/p&gt;
&lt;h3 id=&#34;tauon-music-box&#34;&gt;&lt;a href=&#34;https://tauonmusicbox.rocks/&#34; target=&#34;_blank&#34;&gt;Tauon Music Box&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Is the closest to no-bullshit among all of the ones I&amp;rsquo;ve tried.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/tauon.png&#34;
         alt=&#34;Figure 11: Tauon Music Box screenshot from Flathub&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 11: &lt;/span&gt;Tauon Music Box screenshot from Flathub&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It does support &lt;code&gt;.cue&lt;/code&gt; sheets (wow), and managed to load my music library without many issues.
One of the problems occurred with a three-disk album that doesn&amp;rsquo;t have disk metadata, for some reason.
Every track appeared as a separate album in the list.
But, to be honest, this three-disk album is hard for all other players I&amp;rsquo;ve tried (that support &lt;code&gt;.cue&lt;/code&gt;), not sure why.&lt;/p&gt;
&lt;p&gt;I like this player, but its UI is a bit too flat and too simplistic for my taste.
Like, all of the buttons are just differently arranged rectangles.
I can get used to this, but a bit more clarity wouldn&amp;rsquo;t hurt.
Another small nitpick is that the album grid scrolls in fixed steps, and not fluidly - it just throws me off a bit.&lt;/p&gt;
&lt;p&gt;Other than that - good player, can recommend.&lt;/p&gt;
&lt;h3 id=&#34;qmmp&#34;&gt;&lt;a href=&#34;http://qmmp.ylsoftware.com/&#34; target=&#34;_blank&#34;&gt;Qmmp&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/qmmp.png&#34;
         alt=&#34;Figure 12: Qmmp screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 12: &lt;/span&gt;Qmmp screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Well, most modern players didn&amp;rsquo;t make the cut, let&amp;rsquo;s go back and look at older ones.&lt;/p&gt;
&lt;p&gt;If you want an old Winamp-like player, qmmp is probably what you&amp;rsquo;re looking for.
It supports Winamp skins and acts pretty much the same way.&lt;/p&gt;
&lt;p&gt;It plays everything, has the &lt;code&gt;.cue&lt;/code&gt; support, and the only issue for me is that I can&amp;rsquo;t drag the window with the mouse.
Probably some Wayland/GTK incompatibilities - it&amp;rsquo;s a Qt-based player after all.
I have tried it in the past as well, though I vaguely remember having issues with it here and there.
So I moved to Deadbeef.&lt;/p&gt;
&lt;h3 id=&#34;deadbeef&#34;&gt;&lt;a href=&#34;https://deadbeef.sourceforge.io/&#34; target=&#34;_blank&#34;&gt;Deadbeef&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve previously used Deadbeef, and I think it&amp;rsquo;s one of the best players available on Linux.
I have never used Foobar2000 but as far as I know, Deadbeef is similar to it.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/deadbeef.png&#34;
         alt=&#34;Figure 13: Deadbeef screenshot from the project web page (it doesn&amp;amp;rsquo;t look like this OOTB)&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 13: &lt;/span&gt;Deadbeef screenshot from the project web page (it doesn&amp;rsquo;t look like this OOTB)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;For some reason, it isn&amp;rsquo;t available in the form of a flatpak, so I had to install it inside of a container, similar to Rhythmbox.&lt;/p&gt;
&lt;p&gt;Again, it plays anything and has the &lt;code&gt;.cue&lt;/code&gt; support.
There are many plugins, and this player can be heavily configured.
UI is a bit ugly, but who cares?
And you can stylize it with plugins, replacing any element you don&amp;rsquo;t like.
On my older setup, I had the seek bar replaced with a waveform, kinda like on SoundCloud.
I lost my config years ago and don&amp;rsquo;t want to reconfigure it again, honestly, even if it looks like there are not many changes.&lt;/p&gt;
&lt;p&gt;Still, it has many small problems.
You can&amp;rsquo;t enable album repeat without going into the menu, the play and pause buttons are separate, and you do have to press play to play and pause to pause.
In most players play acts as a pause when the playback is active, and vice versa.&lt;/p&gt;
&lt;p&gt;I like how you can make a simple playlist &lt;em&gt;look&lt;/em&gt; like these are separate albums.
These lines between each album are just separators in a continuous stream of songs, yet, enabling album cover art makes it look even more like separate entries.
It&amp;rsquo;s just an illusion, though, a clever one.&lt;/p&gt;
&lt;h3 id=&#34;audacious&#34;&gt;&lt;a href=&#34;https://audacious-media-player.org/&#34; target=&#34;_blank&#34;&gt;Audacious&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-19-linux-music-players/audacious.png&#34;
         alt=&#34;Figure 14: Audacious screenshot from the project web page&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 14: &lt;/span&gt;Audacious screenshot from the project web page&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Audacious is another good music player.
After a few tweaks in the settings, it looks quite similar to Deadbeef.
Unlike Deadbeef, I couldn&amp;rsquo;t find any way to separate albums in the playlist.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t like playlists, but both Deadbeef and Audacious have an OK playlist experience.
Disabling the column headers helps Audacious a lot, as you basically prevent any shuffling of your playlist by doing so.
So if you&amp;rsquo;ve dragged a folder with songs into the player, and they&amp;rsquo;re in the correct order, you just hit play and you&amp;rsquo;re good.
In some albums, I had tracks imported in the wrong order, and while it is a bummer - it is an easy fix.&lt;/p&gt;
&lt;p&gt;And unlike most other players, Audacious managed to import this three-disk &lt;code&gt;.cue&lt;/code&gt; album and have all disks organized nicely.
That is until I accidentally hit &amp;ldquo;sort by the album&amp;rdquo;, and it grouped all three disks into one album again (after that I disabled the column headers).
What is also weird, is that it doesn&amp;rsquo;t seem to support the disk metadata.&lt;/p&gt;
&lt;h2 id=&#34;skill-issue&#34;&gt;Skill issue?&lt;/h2&gt;
&lt;p&gt;Yeah, yeah, I know, that&amp;rsquo;s a fair point.
But honestly, I don&amp;rsquo;t believe that using a music player should be hard or unintuitive.
The default players in GNOME and KDE do an OK job, to be honest, it&amp;rsquo;s just the fact that they can&amp;rsquo;t play everything I have.&lt;/p&gt;
&lt;p&gt;Remember how it was in the old days?
You pick your CD, tape cassette, or vinyl record, put it into a respective device and you&amp;rsquo;re good.
Yes, you had to swap disks if you wanted to listen to something else, and you couldn&amp;rsquo;t change the order of tracks.
On the other hand, you&amp;rsquo;ve listened to music how the artist intended.&lt;/p&gt;
&lt;p&gt;PC audio players felt liberating back then because you could reorder things, which usually was impossible on the physical medium.
And they had many more features, unavailable on most playback devices back then.
But today, I personally want to go back to a simpler time, but without having to deal with actual CDs.
CDs are good as backups, as I still have some music disks from the 2000s that still work, and I don&amp;rsquo;t have any hard drive from the 2000s that works.
Vinyl is also good, possibly even better to actually preserve data, but it is mastered differently, and I don&amp;rsquo;t have a turntable.&lt;/p&gt;
&lt;p&gt;There are probably many more players I haven&amp;rsquo;t tried, and it&amp;rsquo;s almost impossible to do because there are too many of them.
Again, Tauon Music Box was good, so it&amp;rsquo;s possible to create a modern player, nobody just really wants to.
It does support everything I need, but I didn&amp;rsquo;t really like the UI, to be honest, and it has problems with multi-disk albums.&lt;/p&gt;
&lt;p&gt;The struggle doesn&amp;rsquo;t stop there though.
On Windows, it is a bit better - it has Winamp, AIMP, and Foobar2000.
Mobile devices are, however, in a similar trouble as the Linux desktop - good luck finding a decent no-bullshit local-first music player for Android.
I know, it has AIMP, VLC, and MPV but out of these three only AIMP is a &lt;em&gt;music&lt;/em&gt; player.
There are paid music players too, but I don&amp;rsquo;t know if any of them actually good.
And I don&amp;rsquo;t have an Apple device, so I don&amp;rsquo;t know if it has good non-stock music players.&lt;/p&gt;
&lt;p&gt;So I landed up on Strawberry for now - it works better than everything else, but I&amp;rsquo;d like something a bit simpler.
Seriously, though - bring &lt;code&gt;.cue&lt;/code&gt; support to GNOME Music and it got pretty much everything I need.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Linux Music Players&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 19 Nov 2023 22:57:00 +0300</pubDate>
    </item><item>
      <title>Overcolorization</title>
      <link>https://andreyor.st/posts/2023-11-17-overcolorization/</link>
      <guid>https://andreyor.st/posts/2023-11-17-overcolorization/</guid>
      <description>&lt;p&gt;Tree-sitter became more widespread and Emacs took notice and included a bunch of &lt;code&gt;&amp;lt;lang&amp;gt;-ts-mode&lt;/code&gt; as alternatives to &lt;code&gt;&amp;lt;lang&amp;gt;-mode&lt;/code&gt; into the core.
This is good news and a welcome change, but I have some concerns about the approach.&lt;/p&gt;
&lt;p&gt;When I first saw the Tree-sitter talk by Max Brunsfeld I was concerned that the language &lt;a href=&#34;https://youtu.be/Jes3bD6P0To?t=390&#34; target=&#34;_blank&#34;&gt;highlighting &amp;ldquo;fix&amp;rdquo; they&amp;rsquo;re talking about&lt;/a&gt; is too much.
Here are the screenshots from the talk before and after Tree-sitter:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/before.png&#34;
         alt=&#34;Figure 1: In some languages, variables have different colors depending on context, types have different colors, struct fields don&amp;amp;rsquo;t have their own color, etc.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;In some languages, variables have different colors depending on context, types have different colors, struct fields don&amp;rsquo;t have their own color, etc.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/after.png&#34;
         alt=&#34;Figure 2: Everything is consistent now.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Everything is consistent now.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here&amp;rsquo;s an important quote from that talk:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It might seem like a subtle improvement to you but I really think it actually achieves the goal of making it so that you can kind of get the structure of the code just from glancing at the colors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Structure, from &lt;em&gt;colors&lt;/em&gt;.
I don&amp;rsquo;t know, I have never tried to infer &lt;strong&gt;structure&lt;/strong&gt; from &lt;strong&gt;colors&lt;/strong&gt; in the code.
I do write mostly in lisps today, and to infer structure there I, personally, use semantic indentation, not parentheses, despite a popular belief.
There are people who use colored parentheses to make it easier to see where the expression starts and ends, but in my practice, there&amp;rsquo;s no need for that, and colors can be used for other things.&lt;/p&gt;
&lt;p&gt;Before lisps, I was writing mostly in &lt;a href=&#34;https://en.wikipedia.org/wiki/Generational_list_of_programming_languages#ALGOL_based&#34; target=&#34;_blank&#34;&gt;ALGOL-based&lt;/a&gt; languages, and again, there aren&amp;rsquo;t many places where I could infer &lt;em&gt;structure&lt;/em&gt; from colors.
I don&amp;rsquo;t think I can do that with the provided screenshot of the code in the talk either.
I can see the semantics better, yes, since types and field accesses are uniformly highlighted, but this tells me nothing about code structure - the indentation kinda does.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m being picky here.
The word structure is not the word I have problems with in particular.
And I can get what they mean - you know that the type color is blue, so when you switch languages, and the language defines types at different positions, you can spot them easily, despite being in a different place.
It can be seen when they show C and Go examples on the slides with Tree-sitter highlighting.
While all of that is cool, I think that coloring everything is the wrong approach.&lt;/p&gt;
&lt;p&gt;Before Emacs, I used NeoVim and Kakoune, and I was too obsessed with colors in my editor.
NeoVim by default highlights many things, and I&amp;rsquo;ve even created &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/124dfbc1e255ba646a18b901bf000437539f0e55&#34; target=&#34;_blank&#34;&gt;additional rules&lt;/a&gt; to highlight struct fields in C code.
Kakoune also &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/820ccc844efd874f911983a919495c7e8fe63fc3&#34; target=&#34;_blank&#34;&gt;allowed&lt;/a&gt; me to define my own extra rules and I used it plenty of times.&lt;/p&gt;
&lt;p&gt;But when I moved to Emacs, I noticed that, unlike other editors, syntax highlighting is much more &lt;em&gt;reserved&lt;/em&gt;.
For example, Emacs usually highlights function definitions, but not function calls.
At first, I was upset, and searched for &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/51435e0f4362e947cc996ddf7447fc17a30abd00&#34; target=&#34;_blank&#34;&gt;ways&lt;/a&gt; to enable more syntax highlighting, but quickly learned that the underlying system is slow, and the more you highlight the choppier Emacs gets.&lt;/p&gt;
&lt;p&gt;But after years with Emacs, I began to like the more reserved highlighting.
By highlighting &lt;strong&gt;important&lt;/strong&gt; parts, Emacs helps me focus on important parts of the code.
A function call is not that important, you call them all the time - the definition, however, is.
The macro call, on the other hand, is important, as it transforms the code inside its body, so it is better to know that something that looks like an ordinary call isn&amp;rsquo;t actually an ordinary call.
Rust solved this by forcing the use of &lt;code&gt;!&lt;/code&gt; in macro names, but Emacs had a different solution to the same problem in lisps for a long time by using syntax highlighting.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/elisp-highlighting-specials.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The following screenshot demonstrates how Emacs highlights the macro calls.
The calls to &lt;code&gt;defun&lt;/code&gt;, &lt;code&gt;defmacro&lt;/code&gt;, and &lt;code&gt;when&lt;/code&gt; are calls to macros.
They aren&amp;rsquo;t special language constructs, just macros, but they do affect the language, as they transform the code given to them into something else and that&amp;rsquo;s why it&amp;rsquo;s important to see that you&amp;rsquo;re calling a macro.
Calls to the ordinary functions like &lt;code&gt;apply&lt;/code&gt;, or &lt;code&gt;log-level-satisfies&lt;/code&gt; aren&amp;rsquo;t highlighted because there is not much significance with them - they return some values and that&amp;rsquo;s it.&lt;/p&gt;
&lt;p&gt;The macros above are both standard to and known by Emacs but users can define their own macros.
And we need to somehow highlight these macros as well as already known ones.
Tree-sitter parsers can do that in a very limited way - if the macro comes from the same file it can be detected easily.
If not - you have to analyze all of the files imported by the current file.
Which becomes harder, when files are in external dependencies, possibly in compressed archives, and so on.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s where the dynamic highlighting comes naturally.
Emacs controls everything related to Emacs Lisp so it can do that without much effort, but that can&amp;rsquo;t be said about every other language.&lt;/p&gt;
&lt;p&gt;This is how Emacs highlights the Clojure code for me:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/clojure-var-off.png&#34;
         alt=&#34;Figure 3: No dynamic highlighting&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;No dynamic highlighting&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Emacs can&amp;rsquo;t know anything about Clojure, and thus we can&amp;rsquo;t apply the same logic when it comes to highlighting user-defined macros and other runtime stuff.
But, the CIDER package provides a facility to highlight things dynamically, based on the state of the program.
In this particular case it helps to see that some names came from the global scope:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/clojure-var-on.png&#34;
         alt=&#34;Figure 4: Dynamic highlighting shows a global var&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;Dynamic highlighting shows a global var&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Similarly, CIDER can highlight user-defined macros:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/cider-macro-off.png&#34;
         alt=&#34;Figure 5: Dynamic highlighting is enabled, but the macro wasn&amp;amp;rsquo;t made known to the REPL process&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;Dynamic highlighting is enabled, but the macro wasn&amp;rsquo;t made known to the REPL process&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Same as in Emacs Lisp, Clojure macros are small compilers, so it&amp;rsquo;s better to indicate that certain calls are special:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/cider-macro-on.png&#34;
         alt=&#34;Figure 6: After sending the macro to the REPL, dynamic highlighting shows the user-defined macro&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;After sending the macro to the REPL, dynamic highlighting shows the user-defined macro&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Another use for dynamic highlighting can be found in languages with dynamic scoping, which today are mostly only lisps.
It is important to know if the variable you&amp;rsquo;re using is a dynamically scoped one.
Especially so, when &lt;code&gt;let&lt;/code&gt; can both introduce locals and re-bind dynamically scoped variables.
For example, again, in Emacs Lisp:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/elisp-dynamic-var-off.png&#34;
         alt=&#34;Figure 7: No dynamic highlighting&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 7: &lt;/span&gt;No dynamic highlighting&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The issue here is subtle, but if &lt;code&gt;foo&lt;/code&gt; uses &lt;code&gt;dynamic-var&lt;/code&gt; internally, it will see the value changed to &lt;code&gt;20&lt;/code&gt;.
Dynamic highlighting helps to indicate that &lt;code&gt;dynamic-var&lt;/code&gt; is special and important:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/elisp-dynamic-var-on.png&#34;
         alt=&#34;Figure 8: Dynamic highlighting shows a global var&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 8: &lt;/span&gt;Dynamic highlighting shows a global var&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;m using descriptive names, like &lt;code&gt;local-var&lt;/code&gt; and &lt;code&gt;dynamic-var&lt;/code&gt; but in actual code, it&amp;rsquo;s not as obvious, when something is dynamic.
A few months ago, I encountered a weird bug in one of the projects I maintain, and it was related to dynamic var being used as a local one:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/bug.png&#34;
         alt=&#34;Figure 9: compile-command is a dynamic var&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 9: &lt;/span&gt;&lt;code&gt;compile-command&lt;/code&gt; is a dynamic var&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here, the variable named &lt;code&gt;compile-command&lt;/code&gt; is just a string, used to store a command to compile the source code.
The name is innocent and semantically appropriate.
However, it is a dynamic var introduced in the &lt;code&gt;compile.el&lt;/code&gt; package, and changing &lt;code&gt;compile-command&lt;/code&gt; can cause problems for any functions called from the body of the &lt;code&gt;let&lt;/code&gt; block.
In my case, some other package adviced one of the calls inside this &lt;code&gt;let&lt;/code&gt; block, overriding the &lt;code&gt;compile-command&lt;/code&gt; for them, breaking the package I maintain.&lt;/p&gt;
&lt;p&gt;Sadly, by default, Emacs doesn&amp;rsquo;t highlight such variables.
And, as I said, Tree-sitter can&amp;rsquo;t really help with any of the above cases without parsing &lt;em&gt;all&lt;/em&gt; of the code.
But it often can be achieved with an external package that consults with the runtime, like CIDER for Clojure and &lt;code&gt;highlight-defined.el&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; for Emacs Lisp.
Luckily the fix was easy, but if Emacs highlighted dynamic vars by default, this would not be an issue at all.&lt;/p&gt;
&lt;p&gt;So my point is - highlight the &lt;strong&gt;important stuff&lt;/strong&gt;, not &lt;em&gt;just stuff&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course, for lisps all these nuances existed even before dynamic highlighting, so lisp hackers had to deal with them somehow.
Thus, dynamically scoped vars use different naming conventions (e.g. &lt;code&gt;*dynamic-var*&lt;/code&gt;), macros use different code indentation rules, and so on.
These rules are still widely used today but highlighting is an additional visual aid, making important stuff easier to notice.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;s go back to the main topic.
I&amp;rsquo;ve called this post &amp;ldquo;Overcolorization&amp;rdquo; for a reason, after all.
I wanted to show you the importance of selective highlighting first, and I hope it will make more sense on why I think there is a problem.&lt;/p&gt;
&lt;p&gt;One of the reasons, Emacs highlighting is reserved only for important parts of the code, is because it is slow.
Tree-sitter makes everything much faster, and thus Emacs should be able to highlight everything now without slowdown.
That fact worried me, as it would mean that code could suddenly become a mess of colors when the &lt;code&gt;&amp;lt;lang&amp;gt;-ts-mode&lt;/code&gt; becomes the standard.
I held hopes that due to Emacs being used by generally more conservative people, the old approach to syntax highlighting would remain, what would change is that actually finding the important parts of the code will be easier, because the parser gives us all of the info.&lt;/p&gt;
&lt;p&gt;Recently, I was toying with the Elixir language, and decided to use the now inbuilt &lt;code&gt;elixir-ts-mode&lt;/code&gt;, because the non-tree-sitter mode has issues with automatic indentation, and jumping across the delimiters.
Tree-sitter should naturally fix this, and it indeed does, but &lt;strong&gt;what am I looking at&lt;/strong&gt;?&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-17-overcolorization/elixir.png&#34;
         alt=&#34;Figure 10: elixir-mode on the left, elixir-ts-mode on the right&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 10: &lt;/span&gt;&lt;code&gt;elixir-mode&lt;/code&gt; on the left, &lt;code&gt;elixir-ts-mode&lt;/code&gt; on the right&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Everything is purple.
I&amp;rsquo;ve included the old mode on the left, so you can see what it looked like before I switched to the new one, which is actually &lt;a href=&#34;https://github.com/elixir-editors/emacs-elixir/commit/19ed1ffaccbc14f4b1777a24f0951918bab537b4#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R7-R10&#34; target=&#34;_blank&#34;&gt;suggested by the developers of the original &lt;code&gt;elixir-mode&lt;/code&gt;&lt;/a&gt;.
I mean, it&amp;rsquo;s pretty, and the colors do look nice in my personal opinion, but remember the quote I mentioned?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It actually achieves the goal of making it so that you can kind of get the structure of the code just from glancing at the colors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The colors here clearly do not help the matter here.
You could object by saying, that the colors should be used consistently, and I agree with you, here the main issue is that the &lt;code&gt;font-lock-keyword-face&lt;/code&gt; is used for both keywords and method calls, as well as for parentheses.
The &lt;code&gt;font-lock-function-name-face&lt;/code&gt; is used both for function definitions, parameter names, and calls.
But not for all calls, some use &lt;code&gt;font-lock-keyword-face&lt;/code&gt; and I&amp;rsquo;m not talking about method calls: see &lt;code&gt;raise&lt;/code&gt;.
The &lt;code&gt;font-lock-type-face&lt;/code&gt; is used both for types and &lt;code&gt;:symbols&lt;/code&gt;.
The operators aren&amp;rsquo;t highlighted only because the &lt;code&gt;font-lock-operator-face&lt;/code&gt; is not set in my theme.&lt;/p&gt;
&lt;p&gt;The highlighting is all over the place.
Thanks to the speed and power of the tree sitter the code was made to look pretty, not informative.
The same happened for a few other languages, but Elixir is probably the most offending in my opinion.&lt;/p&gt;
&lt;p&gt;And I can&amp;rsquo;t fix that!
Say, I want to remove highlighting of the method calls - but I can&amp;rsquo;t because for that I need to unset the face used by them, removing highlighting of the language keywords too.
Same with the argument colors - they use function name colors, and I do want to see function definitions highlighted.
I could override the &lt;code&gt;treesit-font-lock-rules&lt;/code&gt; used by Elixir, only the &lt;code&gt;elixir-ts--font-lock-settings&lt;/code&gt; is a private var, and it can silently be removed, renamed, and changed, breaking everything I&amp;rsquo;ve tried to fix.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t want this post to be a bashing of &lt;code&gt;elixir-ts-mode&lt;/code&gt; developers, I&amp;rsquo;m glad that the new mode was made, as it is better in many ways, but the problem with syntax highlighting exists, and other languages are in trouble too.
In Lua, the &lt;code&gt;lua-ts-mode&lt;/code&gt; does highlight table access but doesn&amp;rsquo;t highlight method calls which differs from table access by one symbol.
Are table accesses more important than method calls?
I think they both are equally unimportant.&lt;/p&gt;
&lt;p&gt;The real problem here is that Emacs isn&amp;rsquo;t ready for semantic highlighting.
It does now have Tree-sitter, which is a common interface between most text editors, so the problem isn&amp;rsquo;t with Emacs speed anymore.
What it doesn&amp;rsquo;t have is enough standardized faces to use across all languages.&lt;/p&gt;
&lt;p&gt;Or does it?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;font-lock-comment-face&lt;/code&gt; - face used to highlight comments.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-misc-punctuation-face&lt;/code&gt; - face used to highlight miscellaneous punctuation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-delimiter-face&lt;/code&gt; - face used to highlight delimiters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-bracket-face&lt;/code&gt; - face used to highlight brackets, braces, and parens.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-punctuation-face&lt;/code&gt; - face used to highlight punctuation characters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-property-use-face&lt;/code&gt; - face used to highlight property references.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-property-name-face&lt;/code&gt; - face used to highlight properties of an object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-operator-face&lt;/code&gt; - face used to highlight operators.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-number-face&lt;/code&gt; - face used to highlight numbers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-escape-face&lt;/code&gt; - face used to highlight escape sequences in strings.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-regexp-grouping-construct&lt;/code&gt; - face used to highlight grouping constructs in Lisp regexps.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-regexp-grouping-backslash&lt;/code&gt; - face for backslashes in Lisp regexp grouping constructs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-regexp-face&lt;/code&gt; - face used to highlight regexp literals.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-preprocessor-face&lt;/code&gt; - face used to highlight preprocessor directives.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-negation-char-face&lt;/code&gt; - face used to highlight easy to overlook negation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-warning-face&lt;/code&gt; - face used to highlight warnings.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-constant-face&lt;/code&gt; - face used to highlight constants and labels.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-type-face&lt;/code&gt; - face used to highlight type and class names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-variable-use-face&lt;/code&gt; - face used to highlight variable references.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-variable-name-face&lt;/code&gt; - face used to highlight variable names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-function-call-face&lt;/code&gt; - face used to highlight function calls.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-function-name-face&lt;/code&gt; - face used to highlight function names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-builtin-face&lt;/code&gt; - face used to highlight builtins.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-keyword-face&lt;/code&gt; - face used to highlight keywords.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-doc-markup-face&lt;/code&gt; - face used to highlight embedded documentation mark-up.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-doc-face&lt;/code&gt; - face used to highlight documentation embedded in program code.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-string-face&lt;/code&gt; - face used to highlight strings.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-lock-comment-delimiter-face&lt;/code&gt; - face used to highlight comment delimiters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all of the faces defined in the &lt;code&gt;font-lock.el&lt;/code&gt; package.
There are separate faces for function definitions and function calls - good stuff.
I don&amp;rsquo;t see the face that can be used for method calls specifically, but are there any major differences from ordinary function calls?
It even has a face for variable usage, not just definition.&lt;/p&gt;
&lt;p&gt;Thing is, many of these faces are new, and did not exist prior to Emacs 29.1.
It&amp;rsquo;s good that they were added &lt;a href=&#34;https://git.savannah.gnu.org/cgit/emacs.git/commit/etc/NEWS?id=a795c51f6053272de61bc1721305e3c15ff424ee&#34; target=&#34;_blank&#34;&gt;specifically to be used with Tree-sitter&lt;/a&gt;-based modes.
You can say that I should submit a bug to Emacs about the &lt;code&gt;elixir-ts-mode&lt;/code&gt; not using faces properly, and I did, but the problem isn&amp;rsquo;t specific to &lt;code&gt;elixir-ts-mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Elixir mode is just a convenient way to illustrate the problem
The problem when lifting technical limitations can cause problems.
A famous quote says &amp;ldquo;Limitations breed creativity&amp;rdquo;, and I feel like that&amp;rsquo;s exactly what was going on with the old method of syntax highlighting in Emacs.
It was slow, and couldn&amp;rsquo;t handle too much highlighting or too complex rules, so it was kept to the minimum, highlighting what was absolutely necessary.
But with Tree-sitter parsers being able to process files with 20k lines under 30ms the performance is out of the question.
Well, mostly, you still need to draw everything on the screen, processing abstract syntax trees generated by these parsers.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I want to end this post with a message to fellow major mode maintainers.&lt;/p&gt;
&lt;p&gt;Please, use syntax &lt;strong&gt;highlighting&lt;/strong&gt; to &lt;strong&gt;highlight&lt;/strong&gt;, not to &lt;em&gt;color&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Syntax highlighting is a tool, and highlighting important parts of the code makes programming less convoluted.
Pretty colors are nice to have, but if the point is only to make the code look fancy, there&amp;rsquo;s no real value for what we&amp;rsquo;re trying to do in the end - write better code.
Let&amp;rsquo;s help each other at least at that.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;BTW, &lt;code&gt;highlight-defined.el&lt;/code&gt; by default tries to highlight &lt;em&gt;everything&lt;/em&gt; defined, so I limited it down to only highlighting known dynamic vars.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Overcolorization&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 17 Nov 2023 22:45:00 +0300</pubDate>
    </item><item>
      <title>Why no one uses @media (prefers-color-scheme: dark)?</title>
      <link>https://andreyor.st/posts/2023-11-15-why-no-one-uses-media-prefers-color-scheme-dark/</link>
      <guid>https://andreyor.st/posts/2023-11-15-why-no-one-uses-media-prefers-color-scheme-dark/</guid>
      <description>&lt;p&gt;I don&amp;rsquo;t get it - it&amp;rsquo;s the simplest way to enable dark mode for your website that works across all platforms.
It works on Linux, Android, MacOS, iOS, and maybe even on Windows (I didn&amp;rsquo;t test it, I have no Windows).
I see websites that either use JS to do that or do no dark mode at all.&lt;/p&gt;
&lt;p&gt;Some time ago I started using the &lt;a href=&#34;https://github.com/openstyles/stylus&#34; target=&#34;_blank&#34;&gt;Stylus extension&lt;/a&gt; for Firefox to override CSS for websites that don&amp;rsquo;t do the dark mode.
And you know what?
For a quick fix for most pages, it is as simple as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@&lt;span style=&#34;font-weight:bold&#34;&gt;media&lt;/span&gt; (prefers-color-scheme: dark) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    html { &lt;span style=&#34;font-weight:bold&#34;&gt;filter&lt;/span&gt;: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;invert&lt;/span&gt;(100&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;) &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;hue-rotate&lt;/span&gt;(180&lt;span style=&#34;font-weight:bold&#34;&gt;deg&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    img { &lt;span style=&#34;font-weight:bold&#34;&gt;filter&lt;/span&gt;: &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;invert&lt;/span&gt;(100&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;) &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;hue-rotate&lt;/span&gt;(180&lt;span style=&#34;font-weight:bold&#34;&gt;deg&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, this introduces problems on some pages, for example, embedded videos, especially YouTube ones are hard to invert back.
Images may look horrific if they&amp;rsquo;re done with something else than the &lt;code&gt;img&lt;/code&gt; tag, gradients and colors are preserved but shadows are still inverted, and so on.
But if you have a web page on the web it is you who can do it right, so I don&amp;rsquo;t have to fix it for myself.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scss&#34; data-lang=&#34;scss&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;@media&lt;/span&gt; (prefers-color-scheme: dark) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  body, textarea { color: #dedddc; background-color: #1e1e1e }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  code { background-color: #2b2b2b; color: #dedddc; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pre code { background-color: #ddd; color: #333; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  kbd { background-color: #161b22; color: #dedddc; border: solid 1&lt;span style=&#34;font-weight:bold&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rgb&lt;/span&gt;(57, 63, 71); border-bottom-color: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rgb&lt;/span&gt;(37, 43, 51); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  tbody tr:nth-child(2n+1) td, tbody tr:nth-child(2n+1) th { background-color: #212121; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  table { border: 1&lt;span style=&#34;font-weight:bold&#34;&gt;px&lt;/span&gt; solid #333; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  td, th { border: 1&lt;span style=&#34;font-weight:bold&#34;&gt;px&lt;/span&gt; solid #333; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.post-list&lt;/span&gt; { h1 a { color: #dedddc; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;:hover { color: #7a5fa4; } } }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  a { color: #7a5fa4; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;:hover { color: #7a5fa4; } }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  header h2 { a { color: #86868e &lt;span style=&#34;font-weight:bold&#34;&gt;!important&lt;/span&gt;; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;:hover { color: #7a5fa4 &lt;span style=&#34;font-weight:bold&#34;&gt;!important&lt;/span&gt;; } &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;:active { color: #7a5fa4 &lt;span style=&#34;font-weight:bold&#34;&gt;!important&lt;/span&gt;; } } }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  blockquote { border-left: .25&lt;span style=&#34;font-weight:bold&#34;&gt;em&lt;/span&gt; solid #424242; color: #bebebe; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.org-svg&lt;/span&gt; { filter: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invert&lt;/span&gt;(90&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.invertable&lt;/span&gt; { filter: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invert&lt;/span&gt;(100&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hue-rotate&lt;/span&gt;(180&lt;span style=&#34;font-weight:bold&#34;&gt;deg&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;contrast&lt;/span&gt;(79&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.highlight&lt;/span&gt; { filter: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;invert&lt;/span&gt;(100&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hue-rotate&lt;/span&gt;(180&lt;span style=&#34;font-weight:bold&#34;&gt;deg&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;contrast&lt;/span&gt;(110&lt;span style=&#34;font-weight:bold&#34;&gt;%&lt;/span&gt;); scrollbar-color: #9c9c9c #ddd; background-color: #ddd; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.title-group&lt;/span&gt; { &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.title&lt;/span&gt; { a { color: #dedddc &lt;span style=&#34;font-weight:bold&#34;&gt;!important&lt;/span&gt;; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;:hover { color: #7a5fa4 &lt;span style=&#34;font-weight:bold&#34;&gt;!important&lt;/span&gt;; } &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;:active { color: #7a5fa4 &lt;span style=&#34;font-weight:bold&#34;&gt;!important&lt;/span&gt;; } } } }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  input, input[type=file], button { background-color: #161b22; color: #dedddc; border: solid 1&lt;span style=&#34;font-weight:bold&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rgb&lt;/span&gt;(57, 63, 71); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.diff-added&lt;/span&gt; { background-color: #e2c3da; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.diff-removed&lt;/span&gt; { background-color: #9fe0d6; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is all it takes to make dark mode for this page and the rest of the site.
Yes, I use some &lt;code&gt;filter&lt;/code&gt; attributes for specially constructed images and code, and yes, some browsers may not support it, but it generally works well.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;rsquo;m bringing this up not because I&amp;rsquo;m some freak who wants dark themes everywhere - no.
My PC switches to the dark theme in the evening automatically to be easier on the eyes with the overall brightness, and when I open some web page it often blinds me with a white background.
Not only it is unpleasant, but it is also bad for your health, as at the end of the day your body is more relaxed, and a sudden flash of light forces your eye muscles to suddenly contract.
It&amp;rsquo;s advised not to look at the screen for several hours before bedtime, but I have a lot of work to do after work, so I can&amp;rsquo;t really afford that.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t browse the web &lt;em&gt;that much&lt;/em&gt;, but have a look at the pages I did adjust because I refer to them fairly often:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-11-15-why-no-one-uses-media-prefers-color-scheme-dark/fixes.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Most of these are static pages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is it that hard to add a single &lt;code&gt;@media (prefers-color-scheme: dark) {...}&lt;/code&gt; block to the style file?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, I&amp;rsquo;m not a web developer.
I don&amp;rsquo;t know your ways and such.
You can say that your pages are complicated, your stylesheets are complex and generated with some preprocessor, or you&amp;rsquo;re using some framework that doesn&amp;rsquo;t allow you to do that or whatnot.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll happily take even the stupid invert filter - as long as it is easy on the eyes I&amp;rsquo;m good.
And yes, there are ways of forcing dark mode on everything, so I guess you can pretend there is no issue here, but it is not true.&lt;/p&gt;
&lt;p&gt;Dark mode makes it easier to read stuff in the dark without causing too much eye fatigue - that&amp;rsquo;s the whole point.
Tone your colors down a bit, bring the contrast down so the light text isn&amp;rsquo;t cutting the eyes against a pure black background and you&amp;rsquo;re good.
And please, don&amp;rsquo;t use JS for that, or at least &lt;a href=&#34;https://stackoverflow.com/a/59621903&#34; target=&#34;_blank&#34;&gt;consult&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; with the &lt;code&gt;prefers-color-scheme&lt;/code&gt; query, so that your JS code synchronizes with my system-wide preferences.&lt;/p&gt;
&lt;p&gt;Please add dark mode to your static pages.
It&amp;rsquo;s not that hard.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;The stackoverflow was painfully bright at the time of writing this post&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Why no one uses @media (prefers-color-scheme: dark)?&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 15 Nov 2023 22:50:00 +0300</pubDate>
    </item><item>
      <title>Gamedev marathon</title>
      <link>https://andreyor.st/posts/2023-10-29-gamedev-marathon/</link>
      <guid>https://andreyor.st/posts/2023-10-29-gamedev-marathon/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://andreyor.st/posts/2023-10-19-game4-and-autumn-lisp-game-jam/&#34;&gt;last post&lt;/a&gt; on the subject I mentioned:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…And yeah, I felt burned up a lot, and considered skipping a month maybe…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, yeah.
I left the jam.
And I&amp;rsquo;m stopping my gamedev marathon as well.&lt;/p&gt;
&lt;p&gt;Realizing that it was a struggle rather than a self-motivation attempt helped to make the decision.
Well, yes, I &lt;strong&gt;wanted&lt;/strong&gt; to try this kind of extreme-paced five-month project - it is an interesting experiment.
Not to mention that I kinda accomplished what I wanted, although not really.&lt;/p&gt;
&lt;p&gt;The first month was weird.
First two weeks I wasn&amp;rsquo;t doing anything, because I felt the after-vacation fatigue when you just back from the beach and you have to start working hard immediately.
Then suddenly I felt encouraged and motivated, especially once I had some playable results.
I thought that I was back on track, as I can, in fact, go on a few-month programming frenzy, and do nothing but code in my after-work hours.
And it felt like that, except after I stopped working on Game1, starting to work on Game2 was as hard as with the first one.
So hard, in fact, that I wanted to stop there.&lt;/p&gt;
&lt;p&gt;Game3 was no different, except I made something that can technically be called playable.
I worked for a week on it at most.
It was much simpler than the Game2 on paper, so there were not that many roadblocks to make it work.
After all, no camera movement, no complex coordinate translations, and no procedural generation.
If you&amp;rsquo;ve played Game3 for a minute - you&amp;rsquo;ve seen it all.&lt;/p&gt;
&lt;p&gt;Now, the Game4 was supposed to be a puzzle platformer.
I spent the first week of this month thinking about what kind of puzzles I could make - and I got nothing original.
I&amp;rsquo;m not into puzzle platformers myself, the only one I really enjoyed in the past years was Snakebirds, although it&amp;rsquo;s hard to call it a platformer.
Well, it has gravity and platforms…
Anyway.&lt;/p&gt;
&lt;p&gt;I decided, that since there&amp;rsquo;s an upcoming Fennel game jam, I&amp;rsquo;ll just participate in it, and make another clone of an old game, like I &lt;a href=&#34;https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/&#34;&gt;did&lt;/a&gt; in my first ever jam.
Same as before, I wanted to put a twist on it again, but, well, no game this time.
I left the jam, and I gotta say, for some reason, this button makes it extremely demotivating:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-10-29-gamedev-marathon/doit.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Perhaps I&amp;rsquo;m just too tired.&lt;/p&gt;
&lt;p&gt;Not that I didn&amp;rsquo;t work on the game though.
In the first half of the jam, I tried to make my Game1 bump-based engine work for a Lode Runner-type game.
However, in Lode Runner, you can&amp;rsquo;t jump,  and your movement is tied to a grid - after all, your character creates holes on a grid of tiles.
Modern incarnations of Lode Runner still follow this, so I decided to do the same, as it makes everything just a bit easier.
So I dropped the idea of using work done for Game1 and started from scratch.&lt;/p&gt;
&lt;p&gt;Second half of the jam I spent reworking animations, doing collision detection without Bump and I got a basic skeleton for the game.
But the ladders didn&amp;rsquo;t work properly, the character was somehow clipping through the terrain still, and I was clearly running out of time, so I decided not to torture myself anymore.
I deleted everything and left the jam.
Nothing to show this time.&lt;/p&gt;
&lt;p&gt;My idea for the twist was to make a series of rooms that you can roam free, after you&amp;rsquo;ve collected all gold on the level, and create a grid of levels, similar to rooms in a Metroid-like game.
The goal would be to reach the bottom-right corner of the map, pick up a giant gold piece, and leave through a new set of rooms, as previous ones would be blocked.
Kinda ambitious, and well beyond my skill to be able to do it in a 10-day game jam.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another side to this whole marathon.
Most of the time I simply had no spare time to consistently work on games.
I&amp;rsquo;ve mentioned a few times that life had its own plans for me, and if you know me personally, you know what I mean.
A lot of spontaneous events happened haphazardly during the past three months, and they were both exhausting and demotivating.
Let&amp;rsquo;s just say that I hope I won&amp;rsquo;t have to go through this in another ~10 years.
Perhaps, if not for this, I would have had more time and managed to get Game2 to a playable state and put more effort into Game3.&lt;/p&gt;
&lt;p&gt;On the bright side, now I have some experience in doing animations, implementing a basic player controller, and interactions.
I have future plans for game development, although I don&amp;rsquo;t know if I will go with TIC for that.
TIC is quite limiting, and while I think it&amp;rsquo;s a good thing a times, I felt it tiring most of the time.
The color palette is too small for my liking, screen space is also not the highest.
If there were a 16-bit-like fantasy console, I would probably look at it, but I doubt there are other projects like TIC-80, which are free and open-source, and polished to the same degree.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t get me wrong though, TIC is great for what it offers.
I just want double the resolution, double or quadruple the color palette, double sprite and tile amount, and better sound.
Kind of like we went from NES to SNES - it was so a major step upward that it was hard to look back.
TIC feels like NES to me, and although it is more than NES, I want more than what it gives.
So perhaps I&amp;rsquo;ll stick with LOVE2D in the future.
Or maybe with an entirely different engine, who knows?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll take a few months off from game dev, and then we&amp;rsquo;ll see.
Maybe I&amp;rsquo;ll start working on the game I wanted to make for a long time.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Gamedev marathon&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 29 Oct 2023 15:45:00 +0300</pubDate>
    </item><item>
      <title>You don&#39;t need a terminal emulator</title>
      <link>https://andreyor.st/posts/2023-10-27-you-dont-need-a-terminal-emulator/</link>
      <guid>https://andreyor.st/posts/2023-10-27-you-dont-need-a-terminal-emulator/</guid>
      <description>&lt;p&gt;…if you&amp;rsquo;re an Emacs user, that is.&lt;/p&gt;
&lt;p&gt;You know, it&amp;rsquo;s funny, because people have opinions on why you don&amp;rsquo;t need a terminal on entirely different ends of a spectrum.
It&amp;rsquo;s like that IQ chart meme:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-10-27-you-dont-need-a-terminal-emulator/iq-meme-joke-i-am-not-saying-visual-studio-users-are-dumb.png&#34;
         alt=&#34;Figure 1: *That&amp;amp;rsquo;s Visual Studio on the left, not VS Code&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;*That&amp;rsquo;s Visual Studio on the left, not VS Code&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;And yes, I know, there are many people who will disagree with me, probably on everything that I&amp;rsquo;m going to say next.
But hey, it&amp;rsquo;s OK to agree to disagree.
You don&amp;rsquo;t have to believe me, instead, you should try it for yourself.&lt;/p&gt;
&lt;p&gt;I often see how young programmers walk this kind of path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terminals are scary.&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t need a terminal - my IDE does all things for me with a click of a button.&lt;/li&gt;
&lt;li&gt;Well, I needed a terminal for some kind of task in my latest project and it wasn&amp;rsquo;t so bad.&lt;/li&gt;
&lt;li&gt;GOSH, terminals are so powerful with all these commands available.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;installs Vim&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;OMG, Vim is so powerful and it is a Terminal-base program!&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t need a fancy IDE - I&amp;rsquo;m a power user now!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And many often stop there, which is fine, but a bit sad.
I also been there, but somehow moved on.
Well, not all - some stay within the comfort zone of their IDE which is fine too, some ditch Vim for something more, or even something less, and really become power users.
Mine were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Emacs? Eww, what&amp;rsquo;s that ugly white theme&lt;/li&gt;
&lt;li&gt;Well, Emacs seems interesting, but it starts so slow compared to my 100+ plugins NeoVim setup.&lt;/li&gt;
&lt;li&gt;EVIL mode? Second-floor basement&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;? MAGIT?&lt;/li&gt;
&lt;li&gt;Emacs has wrappings for the tools I use?&lt;/li&gt;
&lt;li&gt;Emacs can run any shell command?&lt;/li&gt;
&lt;li&gt;Even remote ones?&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t need a terminal?&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t need a terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well, I know some people who think alike, so it&amp;rsquo;s not just me, but I do believe that it&amp;rsquo;s not a majority of Emacs users.
The Vterm package for Emacs has 1.6k stars on GitHub at the point of this article, and Emacs itself has several terminal implementations in its core.
So, where I&amp;rsquo;m coming from with this?&lt;/p&gt;
&lt;p&gt;Basically, a few months ago I decided to stop using a terminal emulator.
At all.
I &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/84ad6f46a6309c0b8857eea6c3610f1ba1adc474&#34; target=&#34;_blank&#34;&gt;deleted my Vterm configuration&lt;/a&gt; from Emacs, and since I didn&amp;rsquo;t use terminal outside of Emacs it was pretty much it.
I did keep the &lt;a href=&#34;https://codeberg.org/akib/emacs-eat&#34; target=&#34;_blank&#34;&gt;EAT&lt;/a&gt; package still, as it is sometimes useful for things not so related to terminals directly, but more on that later.&lt;/p&gt;
&lt;p&gt;Now, today I&amp;rsquo;m going to describe why terminal emulators aren&amp;rsquo;t really needed in Emacs specifically, but nothing actually prevents other software from following suit.
It just doesn&amp;rsquo;t happen that often, I guess because most of the time people freak out of non-interactive shells, even though they come with lots of benefits.&lt;/p&gt;
&lt;p&gt;To be clear, yes, my use cases may not cover all of the workflows that involve terminals, however, I think I&amp;rsquo;m covering most of them.
For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I often SSH to remote servers to browse and edit files;
&lt;ul&gt;
&lt;li&gt;More often I&amp;rsquo;m SSH&amp;rsquo;ing to remote servers to run some commands;
&lt;ul&gt;
&lt;li&gt;Sometimes even via multiple hops;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I update existing and install new system packages;&lt;/li&gt;
&lt;li&gt;I run commands on my local machine. Things like:
&lt;ul&gt;
&lt;li&gt;project compilation;&lt;/li&gt;
&lt;li&gt;grepping stuff;&lt;/li&gt;
&lt;li&gt;finding files;&lt;/li&gt;
&lt;li&gt;using things like AWK, Perl, Sed, etc.;&lt;/li&gt;
&lt;li&gt;running servers and services in the background.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, combined, I do both local and remote work, and I don&amp;rsquo;t need a terminal emulator for that.
How?&lt;/p&gt;
&lt;h2 id=&#34;async-shell-command&#34;&gt;&lt;code&gt;async-shell-command&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Emacs has this command, bound by default to &lt;kbd&gt;Alt&lt;/kbd&gt;+&lt;kbd&gt;&amp;amp;&lt;/kbd&gt; (&lt;code&gt;M-&amp;amp;&lt;/code&gt;), and what it does is really simple.
It runs a given command asynchronously in the background, feeding its output to the &lt;code&gt;*Async Shell Command*&lt;/code&gt; buffer.
That&amp;rsquo;s it.
Well, in my case, I&amp;rsquo;m redirecting &lt;code&gt;stderr&lt;/code&gt; to the &lt;code&gt;*Shell Command Errors*&lt;/code&gt; buffer mostly for cases when &lt;code&gt;stdout&lt;/code&gt; is somehow structured.
We&amp;rsquo;ll get to that.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s cool about &lt;code&gt;async-shell-command&lt;/code&gt; is that it basically is a terminal emulator.
Well, not quite, but very close to being that.
Thing is, let&amp;rsquo;s just think about what a terminal emulator is - it&amp;rsquo;s a prompt reading a line, and text spitted between each prompt.
Well, &lt;code&gt;async-shell-command&lt;/code&gt; is basically that, except it doesn&amp;rsquo;t have the prompt in the buffer itself - instead, it&amp;rsquo;s part of Emacs&amp;rsquo; minibuffer.&lt;/p&gt;
&lt;p&gt;And, unlike a terminal emulator, the result of each command is put into the dedicated buffer that you can do all of your usual Emacs operations on.
Ever wondered why things like Tmux implement things like copy-mode?
Because the terminal is interactive by nature and when you need to do non-interactive (by interactive I mean text input and command running) stuff you have to switch to a separate mode.
I don&amp;rsquo;t like separate modes that much.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;async-shell-command&lt;/code&gt; gives you all of the properties of a regular terminal - i.e. it displays text output from a command, and you get a prompt with history and stuff like command/file completions.
If the command requires some input from the user, Emacs will properly accept it in the said buffer - it is interactive.
However, it is not a real terminal emulator still - it can&amp;rsquo;t do TUI stuff.
So if you&amp;rsquo;ve got anything in your workflow that uses TUI &lt;code&gt;async-shell-command&lt;/code&gt; is not the right tool for the job.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll get back to the interactive TUIs in a bit, but I should say that I don&amp;rsquo;t have any such programs in my workflow.
Honestly, if I&amp;rsquo;m already using Emacs, why do I need something TUI-based, if Emacs probably already has a better graphical interface to it?
We&amp;rsquo;ll get to that.&lt;/p&gt;
&lt;h2 id=&#34;compile-and-project-compile&#34;&gt;&lt;code&gt;compile&lt;/code&gt; &amp;amp; &lt;code&gt;project-compile&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s get to the non-interactive interactive stuff.
Earlier I mentioned that non-interactive shells (again, by interactive I mean text input and command running) have some benefits to them but it&amp;rsquo;s often hard to describe what are those to a non-Emacs user.&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;compile&lt;/code&gt; is very similar to &lt;code&gt;async-shell-command&lt;/code&gt; except it doesn&amp;rsquo;t try to process any user input.
Therefore, if you ran something like &lt;code&gt;scp&lt;/code&gt; in a compilation buffer, and forgot to place your SSH key to the machine you&amp;rsquo;re going to copy the file to, you&amp;rsquo;ll be asked for a password, but you won&amp;rsquo;t have any ability to insert it.
It&amp;rsquo;s better to use &lt;code&gt;async-shell-command&lt;/code&gt; for stuff like that.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;project-compile&lt;/code&gt; is exactly the same thing as &lt;code&gt;compile&lt;/code&gt;, except it automatically detects the current project&amp;rsquo;s root directory, and runs from there.
It&amp;rsquo;s very handy to run things like &lt;code&gt;make&lt;/code&gt; because &lt;code&gt;Makefile&lt;/code&gt; is usually located at the project&amp;rsquo;s root.
But, why is it better than &lt;code&gt;async-shell-command&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Well, compilation buffers are pretty specific - they display the log of the compilation process.
That&amp;rsquo;s why we can treat them specially too.
And Emacs does it by default, creating file links to every message in the compilation buffer.
For example, if I run the &lt;code&gt;M-x compile RET main.c RET&lt;/code&gt; with the following &lt;code&gt;main.c&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;works&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We get the following buffer:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-10-27-you-dont-need-a-terminal-emulator/compilation-buffer.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;As can be seen here, each warning is highlighted with a respectful color, like notes use a teal color, and warnings are yellow.
But that can be done by terminals too, you might say.
Note, however, that when I hover my mouse over such colored text it shows up as a link that I can click.
Upon clicking it, Emacs will open that file and highlight the error.&lt;/p&gt;
&lt;p&gt;Well, it might not be as impressive as it sounds, but this is an open interface.
You can add support for any kind of language you want, and it will work.
I have a post, &lt;a href=&#34;https://andreyor.st/posts/2023-10-03-compiling-clojure-projects-in-emacs-jumping-into-dependencies/&#34;&gt;describing&lt;/a&gt; how I&amp;rsquo;ve added support for Clojure, and went as far as searching for warnings inside dependencies stored as &lt;code&gt;.jar&lt;/code&gt; archives in my &lt;code&gt;.m2&lt;/code&gt; cache.
It&amp;rsquo;s nuts how flexible this system is.&lt;/p&gt;
&lt;p&gt;Similarly, if you run &lt;code&gt;M-x project-compile RET grep -Rn &amp;quot;something&amp;quot; RET&lt;/code&gt; it will create a compilation buffer with the results from &lt;code&gt;grep&lt;/code&gt;, and each result will be a clickable link:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-10-27-you-dont-need-a-terminal-emulator/compile-grep.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You don&amp;rsquo;t need to click on links either, you can use &lt;kbd&gt;n&lt;/kbd&gt; or &lt;kbd&gt;p&lt;/kbd&gt; to go to the next link, and automatically open the file at the link&amp;rsquo;s specified position.
But running &lt;code&gt;grep&lt;/code&gt; and other tools through the compilation buffer is a bit cumbersome, as you do have to follow a specific line format that this buffer understands.
Instead, you can use &lt;code&gt;Xref&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;xref&#34;&gt;Xref&lt;/h2&gt;
&lt;p&gt;Another thing provided by Emacs, mainly for reference navigation purposes, but extensible enough that you can make it do whatever you want.
For instance, you can run such things like &lt;code&gt;grep&lt;/code&gt; right from Emacs, and get results in the &lt;code&gt;*xref*&lt;/code&gt; buffer:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-10-27-you-dont-need-a-terminal-emulator/xref-grep.png&#34;
         alt=&#34;Figure 2: result of calling project-find-regexp which internally uses grep&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;result of calling &lt;code&gt;project-find-regexp&lt;/code&gt; which internally uses &lt;code&gt;grep&lt;/code&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Similarly to the compilation buffer, you get the same set of shortcuts to move around, but a more readable and categorized output.
And this works for many other things, like results from your language servers, tag files, etc.
Even more than that, you can do stuff like &lt;code&gt;xref-query-replace-in-results&lt;/code&gt; from the &lt;code&gt;*xref*&lt;/code&gt; buffer - so it can act like Sed.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s my point - these tools are great, but using them from the terminal is not fun.
Emacs acknowledges that these tools are great, and provides a better interface for them without requiring you to run a terminal emulator inside Emacs.
To be fair, Emacs isn&amp;rsquo;t the only one who does this - but I find it to be the most consistent and most flexible in this regard.&lt;/p&gt;
&lt;p&gt;But what if you need to do stuff with remote machines?&lt;/p&gt;
&lt;h2 id=&#34;tramp&#34;&gt;TRAMP&lt;/h2&gt;
&lt;p&gt;So, we&amp;rsquo;ve covered basic tasks involving running various commands on your local machine.
The &lt;code&gt;async-shell-command&lt;/code&gt; can be used to run arbitrary commands and those which require some level of interactivity.
The &lt;code&gt;compile&lt;/code&gt; command is for project compilation stuff, and &lt;code&gt;Xref&lt;/code&gt; is for navigating references provided by some other tools or Emacs itself.
Now imagine we need to run &lt;code&gt;grep&lt;/code&gt; on the remote - how would we do that?&lt;/p&gt;
&lt;p&gt;&lt;abbr title=&#34;Transparent Remote (file) Access, Multiple Protocol&#34;&gt;TRAMP&lt;/abbr&gt; got you covered.
When opening a file in Emacs you can start the path with a forward slash &lt;code&gt;/&lt;/code&gt; followed by a protocol, like &lt;code&gt;ssh&lt;/code&gt; and Emacs will open a remote file for you.
For example &lt;code&gt;/ssh:user@host:/home/user/.bashrc&lt;/code&gt; will open the &lt;code&gt;.bashrc&lt;/code&gt; file on the remote machine if you have access to that.
If not, Emacs will ask for the password, and it is basically the same as the &lt;code&gt;ssh&lt;/code&gt; in the terminal.&lt;/p&gt;
&lt;p&gt;But now, when you&amp;rsquo;ve opened a file via the TRAMP, suddenly, you can use all these things I&amp;rsquo;ve been talking about before - &lt;code&gt;async-shell-command&lt;/code&gt;, &lt;code&gt;compile&lt;/code&gt;, &lt;code&gt;project-find-regexp&lt;/code&gt; and it will do its work on the remote.
It&amp;rsquo;s really transparent.&lt;/p&gt;
&lt;p&gt;More than that - if you have a remote machine, and it has something like a language server installed, Emacs will not try to run your local machine&amp;rsquo;s language server (if it even has one), instead, it will run it on the remote.
This means that you can run Emacs on your machine, but have all of the development stuff needed on the remote.
And you don&amp;rsquo;t need to run Emacs remotely, or do X over ssh, or use things like &lt;code&gt;sshfs&lt;/code&gt; - just use TRAMP.&lt;/p&gt;
&lt;p&gt;And TRAMP isn&amp;rsquo;t limited to just &lt;code&gt;ssh&lt;/code&gt;.
You can enter containers as well, e.g. opening a file with &lt;code&gt;/podman:container-name:/path/to/file&lt;/code&gt; will give you access to files and programs in a container.
And there are many more methods that TRAMP supports, so you&amp;rsquo;re probably well covered for your particular remote accessing needs.
As for me, instead of SSH&amp;rsquo;ing to a machine I just open it in &lt;abbr title=&#34;&lt;b&gt;Dir&lt;/b&gt;ectory &lt;b&gt;Ed&lt;/b&gt;itor&#34;&gt;DIRED&lt;/abbr&gt; via TRAMP, and run commands using &lt;code&gt;async-shell-commands&lt;/code&gt; most of the time.&lt;/p&gt;
&lt;p&gt;Yes, TRAMP can be slow, but I haven&amp;rsquo;t noticed that in my practice.
It depends on the connection speed, and when I do my work, all remote machines are usually in the same network.
Your case may vary.&lt;/p&gt;
&lt;p&gt;But I can&amp;rsquo;t stress this enough - you don&amp;rsquo;t need a terminal emulator for the task of editing remote files or running commands.&lt;/p&gt;
&lt;p&gt;Imagine this - I have to work with remote machines created by other people.
They&amp;rsquo;re set up from an arbitrary Linux image, not all of them even have Vim - only stripped down &lt;code&gt;vi&lt;/code&gt;.
So if I were to &lt;code&gt;ssh&lt;/code&gt; to them and run &lt;code&gt;vi&lt;/code&gt; I would probably be bald now, because &lt;code&gt;vi&lt;/code&gt; is terrible, and if your terminfo isn&amp;rsquo;t supported by the remote you get gibberish symbols here and there when interacting with &lt;code&gt;vi&lt;/code&gt; or even the shell some times.
And believe me, I know how to use &lt;code&gt;vi&lt;/code&gt; and Vim, I used them for many years prior to Emacs - I just don&amp;rsquo;t want to anymore.&lt;/p&gt;
&lt;p&gt;So every time I hear things like: &amp;ldquo;Yeah, Emacs is cool, but I have to SSH to headless remotes and edit files, so Vim is a more fitting choice for me&amp;rdquo;, I say: &amp;ldquo;No. No it isn&amp;rsquo;t&amp;rdquo;.
And even if that&amp;rsquo;s the case - by SSH&amp;rsquo;ing to a remote, you lose your Vim configuration - you either get a pure Vim or sometimes even just a plain &lt;code&gt;vi&lt;/code&gt;.
When I was using Vim, not having my config around was annoying, because I had many handy keybindings, helpful plugins for navigation, and so on.
So instead of SSH&amp;rsquo;ing, I used &lt;code&gt;sshfs&lt;/code&gt; to mount the remote.
This can work, until you need to execute something on the remote - then you still need to use SSH.&lt;/p&gt;
&lt;p&gt;With Emacs - I don&amp;rsquo;t.&lt;/p&gt;
&lt;h2 id=&#34;tuis&#34;&gt;TUIs&lt;/h2&gt;
&lt;p&gt;Now, let&amp;rsquo;s get back to the elephant in the room.
Running &lt;code&gt;grep&lt;/code&gt; and other stuff is fun and all but we can&amp;rsquo;t leave out programs that use a TUI - Terminal User Interface.&lt;/p&gt;
&lt;p&gt;I often see people running &lt;code&gt;mc&lt;/code&gt; (Midnight Commander), some use TUI Git clients, and many find &lt;code&gt;fzf&lt;/code&gt; very useful.
And yeah, neither &lt;code&gt;async-shell-command&lt;/code&gt; nor &lt;code&gt;compile&lt;/code&gt; can run those.
If I try to run &lt;code&gt;mc&lt;/code&gt; from the former, I get this message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Your terminal lacks the ability to clear the screen or position the cursor.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s reasonable, it&amp;rsquo;s just a text buffer, not a terminal emulator, as I&amp;rsquo;ve mentioned.&lt;/p&gt;
&lt;p&gt;However, why would you run &lt;code&gt;mc&lt;/code&gt; if you have DIRED in Emacs?
Same with the TUI Git clients - MAGIT blows those out of the water.
FZF?
Emacs has multiple completion narrowing and filtering frameworks that integrate with the rest of Emacs, so I don&amp;rsquo;t see why would I need to use &lt;code&gt;fzf&lt;/code&gt; specifically.
And if you want - you can, there&amp;rsquo;s a package that integrates with it.&lt;/p&gt;
&lt;p&gt;So, my point is - most of the time, there is either a package providing a superior experience to the one that the TUI app provides.
And it&amp;rsquo;s still text - you can use all of your Emacs operations on it, like on a regular buffer, same as in a terminal, just less clunky.&lt;/p&gt;
&lt;p&gt;Also, remember how I said that I install system packages from Emacs?
Well, package managers usually don&amp;rsquo;t have a TUI, so I do it from &lt;code&gt;async-shell-command&lt;/code&gt; which allows me to interactively use my system&amp;rsquo;s package manager.
But, if I were a GNU Guix user, I &lt;a href=&#34;https://guix.gnu.org/en/blog/2014/emacs-as-a-general-purpose-package-manager/&#34; target=&#34;_blank&#34;&gt;could use Emacs&lt;/a&gt; to get an interface similar to the one you get with &lt;code&gt;package.el&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-10-27-you-dont-need-a-terminal-emulator/package.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;So yeah, Emacs is able to give you a better interface to your tools than a terminal emulator.
And if not, which I&amp;rsquo;m yet to see, you &lt;em&gt;can run a shell&lt;/em&gt; in Emacs.&lt;/p&gt;
&lt;p&gt;Wait, wait, I said you can run a shell, not a terminal emulator.
That doesn&amp;rsquo;t count, right?&lt;/p&gt;
&lt;h2 id=&#34;eshell&#34;&gt;Eshell&lt;/h2&gt;
&lt;p&gt;Emacs has its own shell, written in Emacs lisp, that works across multiple operating systems.
It is called &lt;code&gt;eshell&lt;/code&gt; and it is great.
You can extend it with Emacs Lisp, you can write scripts in Emacs Lisp, and it still has access to all of the other tools you use regularly.
But again, it is not a terminal emulator, it is a shell.
Like &lt;code&gt;bash&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if we try to run a program that requires terminal capabilities specifically, Eshell will automatically create a separate buffer that runs an ANSI terminal emulator, also written in Emacs Lisp.
Which means that your interactive TUI programs &lt;em&gt;should&lt;/em&gt; run fine.
In practice, it isn&amp;rsquo;t always great.&lt;/p&gt;
&lt;p&gt;However, recently I&amp;rsquo;ve found this package: &lt;a href=&#34;https://codeberg.org/akib/emacs-eat&#34; target=&#34;_blank&#34;&gt;EAT&lt;/a&gt;.
It is a terminal emulator that can run inside an Eshell buffer - meaning that you don&amp;rsquo;t have to deal with separate buffers and such if you happen to run a command that requires a proper terminal.
Of course, you can use EAT as a terminal emulator by itself, but I don&amp;rsquo;t find this that useful.
Instead, I use it from Eshell, although very rarely too.
It&amp;rsquo;s just a nice backup.&lt;/p&gt;
&lt;h2 id=&#34;what-are-the-tasks-you-believe-you-need-a-terminal-for&#34;&gt;What are the tasks you believe you need a terminal for?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m genuinely interested, feel free to contact me and share your thoughts.
Or if you tried the ones I&amp;rsquo;ve provided and it wasn&amp;rsquo;t better, or if you just think that they won&amp;rsquo;t work for you - we can chat about that too.&lt;/p&gt;
&lt;p&gt;I found myself on this weird path just a few months ago, but these were very busy months.
Meaning, I think I have enough experience with this way of doing things to say that it is good.
Again, I work with remote machines all the time, and I have to transfer files to them, edit remote files, watch logs live as the services are running, do remote development and more.
And I do it from TRAMP with the help of &lt;code&gt;async-shell-command&lt;/code&gt; and nothing else.
For local tasks, I use &lt;code&gt;project-compile&lt;/code&gt; and other project-related functions.&lt;/p&gt;
&lt;p&gt;At first, it wasn&amp;rsquo;t as seamless, but I got adjusted quickly.
Yes, I felt the urge to run Vterm, and SSH from there at first - but as time went by I noticed that opening TRAMP is much easier, as it reuses the already familiar Emacs&amp;rsquo; file prompt.
And the same goes for every other command I do.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a shame that most other software I know doesn&amp;rsquo;t do this kind of integration.
Visual Studio Code just gives you an integrated terminal - which is no different from an ordinary terminal.
And in the case of Linux, probably isn&amp;rsquo;t the greatest terminal either.
IntelliJ IDEA does that too, and while their terminal tries to do some smart things, I find it inconsistent.&lt;/p&gt;
&lt;p&gt;The same goes for other code editors, like Vim which also now has an integrated terminal.
Though running a terminal from a terminal-based editor is weird - you&amp;rsquo;re one &lt;code&gt;^Z&lt;/code&gt; away from your shell anyway.
And for multiplexing needs, you can always use Tmux, which again, is probably better than the integrated terminal.&lt;/p&gt;
&lt;p&gt;Kakoune is an interesting case here, they have a similar idea to Emacs - you can run commands and pipe their output to a buffer to later process it.
And because there&amp;rsquo;s no extension language in Kakoune, it&amp;rsquo;s the primary way of adding features to the editor.
E.g. you can&amp;rsquo;t implement a fuzzy file picker in Kakscript - you gotta use &lt;code&gt;fzf&lt;/code&gt; for that.
And while that&amp;rsquo;s a great way of handling this, I would say it&amp;rsquo;s better than how Vim handles this, I still think that it&amp;rsquo;s not as good as what Emacs does.
But Emacs is an old project, it had time to develop all of that, while Kakoune is still young.&lt;/p&gt;
&lt;p&gt;Well, that&amp;rsquo;s it.
Feel free to share your thoughts, disagree with me, or whatnot.
I think I&amp;rsquo;m now a firm believer that terminals need to die off at this point.
A superior integration is possible, and already available.
Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;arbitrary Metal Gear Solid reference&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: You don&#39;t need a terminal emulator&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 27 Oct 2023 20:12:00 +0300</pubDate>
    </item><item>
      <title>Game4 and Autumn Lisp Game Jam</title>
      <link>https://andreyor.st/posts/2023-10-19-game4-and-autumn-lisp-game-jam/</link>
      <guid>https://andreyor.st/posts/2023-10-19-game4-and-autumn-lisp-game-jam/</guid>
      <description>&lt;p&gt;You might be wondering why there were no posts on the game development marathon I&amp;rsquo;ve been doing.
Maybe you&amp;rsquo;d thought that I gave up after the admittedly underwhelming game3 having no actual game just some basic movement.
And yeah, I felt burned up a lot, and considered skipping a month maybe - but then &lt;a href=&#34;https://itch.io/jam/autumn-lisp-game-jam-2023&#34; target=&#34;_blank&#34;&gt;this happened&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I thought - well, I just make the game during the game jam instead, and rest up until the jam begins.
Yes, it means I will technically have less time to do this, but I did spend even less time on game dev last month, so it&amp;rsquo;s fine.
I also got an unplanned vacation, so I guess I&amp;rsquo;ll actually have free time too.&lt;/p&gt;
&lt;p&gt;Though, I lied a bit.
The other reason I didn&amp;rsquo;t do anything is also because the next genre I wanted to work in is a puzzle platformer.
And honestly, I don&amp;rsquo;t know what kind of puzzles to make.
None seem appealing.&lt;/p&gt;
&lt;p&gt;So after a bit of consideration, I&amp;rsquo;ve decided that can try to make something like a &lt;a href=&#34;https://en.wikipedia.org/wiki/Lode_Runner&#34; target=&#34;_blank&#34;&gt;Lode Runner&lt;/a&gt; type of game.
I already have the platformer engine from the very first game in this series, and originally I&amp;rsquo;ve planned that I would make a really simple 2D platformer, then in the subsequent game I will refine and improve it.
Similarly, with the top-down games - first make a simple dungeon crawler, then take the blueprint and make an adventure with it.
Unfortunately, the second game was a flop, and thus if I am to make the fifth game I&amp;rsquo;ll have to do everything from scratch.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve been thinking how I should handle the game.
I guess I&amp;rsquo;m going to ditch the camera here, so the level fits the screen.
It will make it a bit easier to reason about, and I guess I can always add camera back later if I really need to.&lt;/p&gt;
&lt;p&gt;AI would be an issue though - I&amp;rsquo;ll need to implement some kind of path-finding for the 2D grid with gravity in mind.
In other words, enemies should understand that they can jump down from cliffs if it will bring them on the same elevation with the player.
Additionally, enemies shouldn&amp;rsquo;t just follow the shortest path to the player, as it will make them very predictable.&lt;/p&gt;
&lt;p&gt;And if I have time, I can try putting on a twist to the formula.
Not sure what kind of twist yet, but we&amp;rsquo;ll see I guess.&lt;/p&gt;
&lt;p&gt;The jam starts in ~12 hours, which unfortunately means that it will begin while my work week isn&amp;rsquo;t yet ended.
So I will have one day less already.
Additionally, right now I&amp;rsquo;m in another city, and will lose another day on train to get back home.
So this leaves me with 8 days instead of 10.&lt;/p&gt;
&lt;p&gt;Hopefully it will not be an issue.
Wish me luck!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game4 and Autumn Lisp Game Jam&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 19 Oct 2023 18:42:00 +0300</pubDate>
    </item><item>
      <title>A programming system</title>
      <link>https://andreyor.st/posts/2023-10-18-a-programming-system/</link>
      <guid>https://andreyor.st/posts/2023-10-18-a-programming-system/</guid>
      <description>&lt;p&gt;Not to be confused with a programming &lt;em&gt;language&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I would like to cover what features I think a dynamic language environment should have.
Or to rephrase that, what would the environment probably have if I were to design it.&lt;/p&gt;
&lt;p&gt;I like small systems - when something is small and comprehensible, it&amp;rsquo;s easier to reason about its use.
That&amp;rsquo;s partly the reason I like languages like Lua.
And working with Lua actually motivated me to start thinking about writing my own bytecode interpreter.
But more on that later.&lt;/p&gt;
&lt;p&gt;When it comes to programming languages and their environments, the situation usually isn&amp;rsquo;t great.
A lot of quirks exist, mostly due to the time period the system has been designed, or because the original scope of the system shifted and now the legacy design decisions show.
For most people, these things are tolerable or already unnoticeable - some even go as far as to defend quirks of the system, as if it was a feature.
Like weak typing in JavaScript, allowing one to add two empty arrays, and get an empty string as a result.
But I digress.&lt;/p&gt;
&lt;p&gt;I must say, there are many compelling systems in the programming field.
By systems, I mostly mean the language runtime or a virtual machine/bytecode interpreter it hosts on, but in actuality it&amp;rsquo;s a bit more than that.
Yes, each system almost always comes with some &lt;em&gt;first-party&lt;/em&gt; language, think JVM and Java, BEAM and Erlang, often tightly coupled together, making it hard to separate the two, but not always.
In fact, the systems I&amp;rsquo;ve mentioned are not tightly coupled at all!&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s dive in.
I&amp;rsquo;ll briefly list systems I know enough to have some sort of opinion on.
Don&amp;rsquo;t take me too seriously, though, as I&amp;rsquo;m not taught in compiler design, and only read a few books on the subject.
If anything I say here is wrong just &lt;a href=&#34;https://andreyor.st/about#links&#34;&gt;reach&lt;/a&gt; me out, and we&amp;rsquo;ll see if I can fix the text, or just remove it adding a note.&lt;/p&gt;
&lt;h3 id=&#34;scheme&#34;&gt;Scheme&lt;/h3&gt;
&lt;p&gt;If you read my blog regularly, you know I love lisps.
Can&amp;rsquo;t say so for Scheme.
Weird, right?
That&amp;rsquo;s mostly related to the language itself, and this topic focuses on the other side of things.&lt;/p&gt;
&lt;p&gt;Scheme is a small system.
It is standardized, and the standard itself is not very big.
This is both an upside and a downside - because the standard is easy to implement, there are IMO too many implementations.
Each implementation is slightly different, and not always compatible, which makes it harder to choose one.&lt;/p&gt;
&lt;p&gt;For example, I don&amp;rsquo;t want to commit to, say, Guile, and much later find that in retrospect Chez was a better choice.
Or Racket, or Chicken, or Gambit, or MIT Scheme, or s7, or Cyclone, or Microscheme, or Loko Scheme, or Kawa, or whatever.
Even I have a Scheme-like language, though it has nothing to do with the standard, and I would not consider it a real Scheme.
Still, some code can be just copied to it, and it will hopefully work.&lt;/p&gt;
&lt;p&gt;Though, even though I just said that the topic of the post isn&amp;rsquo;t about language itself, I feel like getting this out of my system.
The other problem I have with Scheme as a language is that its default feature set is just weird.
I mean, the language that processes &lt;strong&gt;lists&lt;/strong&gt; doesn&amp;rsquo;t feature most list processing functions out of the box - it&amp;rsquo;s a part of &lt;a href=&#34;https://www.gnu.org/software/guile/manual/html_node/SRFI_002d1.html&#34; target=&#34;_blank&#34;&gt;SRFI-1&lt;/a&gt;.
Yes, it&amp;rsquo;s as hard as doing &lt;code&gt;(use-modules (srfi srfi-1))&lt;/code&gt; but why a &lt;strong&gt;list library&lt;/strong&gt; is in a &lt;abbr title=&#34;Scheme Request For Implementation&#34;&gt;SRFI&lt;/abbr&gt; is beyond me.
But I digress, again.&lt;/p&gt;
&lt;p&gt;So, yeah, not a huge fan of Scheme the language, but the Guile VM is pretty neat!
It&amp;rsquo;s a compiler tower-based system, meaning that you can implement other languages for Guile virtual machine if you define your language to compile to the one supported by the compiler tower.
For example, there are implementations for &lt;a href=&#34;https://gitlab.com/NalaGinrut/guile-lua-rebirth&#34; target=&#34;_blank&#34;&gt;Lua&lt;/a&gt; and &lt;a href=&#34;https://www.gnu.org/software/guile/manual/html_node/ECMAScript.html&#34; target=&#34;_blank&#34;&gt;ECMAScript&lt;/a&gt;.
And just recently there were news that the Guile &lt;a href=&#34;https://spritely.institute/news/guile-hoot-v010-released.html&#34; target=&#34;_blank&#34;&gt;got a WASM backend&lt;/a&gt;!
Which is great, and as far as I understand, because of how Guile is structured, other languages implemented for higher levels of the tower will be able to compile to WASM as well.
You can read more on the whole compilation process &lt;a href=&#34;https://www.gnu.org/software/guile/manual/html_node/Compiling-to-the-Virtual-Machine.html&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other important characteristics of Guile is that it is dynamic, like most other lisps, and that it supports &lt;a href=&#34;https://www.gnu.org/software/guile/manual/html_node/Continuations.html&#34; target=&#34;_blank&#34;&gt;continuations&lt;/a&gt; and &lt;a href=&#34;https://www.gnu.org/software/guile/manual/html_node/Prompt-Primitives.html&#34; target=&#34;_blank&#34;&gt;delimited continuations&lt;/a&gt;, which are a great feature that can be used to implement all sorts of control flow operators.
Additionally, Guile now has a &lt;a href=&#34;https://wingolog.org/archives/2013/11/26/a-register-vm-for-guile&#34; target=&#34;_blank&#34;&gt;register-based VM&lt;/a&gt;, which makes it generally faster than other bytecode interpreters because less bytecode instructions are required.
But let&amp;rsquo;s move on to other lisp system.&lt;/p&gt;
&lt;h3 id=&#34;lisp&#34;&gt;Lisp&lt;/h3&gt;
&lt;p&gt;Same as Scheme, it&amp;rsquo;s a standardized language, albeit its standard is much bigger than Scheme&amp;rsquo;s.
And in terms of system complexity the situation is similar - Lisp is bigger, yet not as complex as many other systems.&lt;/p&gt;
&lt;p&gt;As for its implementations, there&amp;rsquo;s Common Lisp, which many lispers refer to as just Lisp, and they don&amp;rsquo;t like when other languages with parentheses around the calls are called lisps.
And same as with Scheme, there are many implementations of Common Lisp - SBCL, CCL, ECL, ABCL, ClozureCL, and others.
I&amp;rsquo;m a bit familiar with Common Lisp on SBCL, and toyed with the language enough to know some of its quirks and differences with other implementations.
That is, I&amp;rsquo;m not an expert, far from it, so take my words with a grain of salt.
The full Common Lisp system is hard to grasp, but it&amp;rsquo;s been ironed over time a lot, and it is comprehensible thanks to the standard.&lt;/p&gt;
&lt;p&gt;What I like about Common Lisp systems is that they can work with Lisp &lt;strong&gt;images&lt;/strong&gt;.
Creating an image means that you tell the Lisp system to create an image of its current state, write it to the disk, and then later you can restore it, continuing like nothing happened.&lt;/p&gt;
&lt;p&gt;I should have mentioned that I&amp;rsquo;m not going to go into every system listing all of its features - instead, I&amp;rsquo;m going to list ones that I think are important and make the difference.&lt;/p&gt;
&lt;p&gt;Another such component of Common Lisp are conditions.
I&amp;rsquo;m not sure if they&amp;rsquo;re implemented in the VM, but probably it is how it&amp;rsquo;s done, as they have to be performant.
Conditions are like exceptions, except they&amp;rsquo;re three-part instead of two-part.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another widely used Lisp system, perhaps even more than Common Lisp - Emacs.
I guess it&amp;rsquo;s not a fair to compare a text editor to a Lisp runtime, but Emacs is not an editor, so we&amp;rsquo;re good.
Some would argue that Emacs Lisp isn&amp;rsquo;t cut to be used as a general-purpose language, but there were large systems, &lt;a href=&#34;https://www.reddit.com/r/emacs/comments/lly7po/do_you_use_emacs_lisp_as_a_general_purpose/gnvzisy/&#34; target=&#34;_blank&#34;&gt;entirely unrelated&lt;/a&gt; to Emacs, written in it, so it can be used in this way.
Though many, probably, will think that you&amp;rsquo;re crazy for doing that.&lt;/p&gt;
&lt;p&gt;Honestly, there aren&amp;rsquo;t many unique properties of Emacs Lisp I know of, in this regard it is pretty generic.
But I still wanted to bring it up, as Emacs itself is a perfect example of a &lt;strong&gt;programming system&lt;/strong&gt;.
There&amp;rsquo;s a saying that Emacs is &lt;a href=&#34;https://en.wikipedia.org/wiki/Editor_war#Humor&#34; target=&#34;_blank&#34;&gt;a great operating system, lacking only a decent editor&lt;/a&gt;, and while it&amp;rsquo;s a joke I don&amp;rsquo;t think it is true - the editor is pretty great.&lt;/p&gt;
&lt;p&gt;Emacs is almost everything I could ask for when it comes to a system that I can program.
I have a &lt;a href=&#34;https://andreyor.st/posts/2023-07-11-emacs-gui-library/&#34;&gt;post&lt;/a&gt; describing my take on a possible GUI library for the Emacs system, but apart from that, Emacs is very customizable and programmable.
I think the main reason for that is not the fact that it is a dynamic system, but that it has such feature as &lt;strong&gt;advice&lt;/strong&gt;.
Advises in Emacs allow anyone to redefine or wrap any function, making it possible to patch existing code without modifying it.
I know that Common Lisp has a similar thing, but I think in Emacs it is much more common to do it than in other large Lisp applications.&lt;/p&gt;
&lt;h3 id=&#34;jvm&#34;&gt;JVM&lt;/h3&gt;
&lt;p&gt;Unpopular opinion - JVM is good.
Like, &lt;strong&gt;really good&lt;/strong&gt;.
JVM is fast, portable, and scales well.
And the library ecosystem is HUGE.&lt;/p&gt;
&lt;p&gt;Contrary to popular belief because nearly all mainstream JVM-based languages are statically typed - the JVM itself is dynamic, which makes possible languages like Clojure to exist on it alongside with Java or Scala.
And it&amp;rsquo;s a system that is known for its backward compatibility guarantees.
I think that&amp;rsquo;s the main reason why Clojure compiler can generate bytecode, instead of translating Clojure to Java and then using JVM to compile it, like many languages targeting other platforms do nowadays.&lt;/p&gt;
&lt;p&gt;And I&amp;rsquo;m not sure if there are many other systems that allow for that.
Elixir &lt;a href=&#34;https://elixir-lang.org/crash-course.html#adding-elixir-to-existing-erlang-programs&#34; target=&#34;_blank&#34;&gt;seems to be compiled&lt;/a&gt; to BEAM bytecode, but I can&amp;rsquo;t actually find if it is really done this way.
For example, nearly &lt;a href=&#34;https://github.com/hengestone/lua-languages&#34; target=&#34;_blank&#34;&gt;all languages&lt;/a&gt; that target the Lua VM just compile to Lua, not to the Lua bytecode - perhaps because Lua bytecode is not compatible between different releases.&lt;/p&gt;
&lt;p&gt;I like JVM for its promise, but on the other hand it&amp;rsquo;s pretty huge.
Slimmed down versions of JVM existed, but it&amp;rsquo;s not the same, as just being small and embeddable, which I also value greatly.
Still, the capabilities JVM provide are great - it has a lot of state-of-the-art technology in it, making it viable as a runtime for high performance high throughput applications.&lt;/p&gt;
&lt;p&gt;Maybe JVM isn&amp;rsquo;t everyone&amp;rsquo;s cup of tea, but I think it&amp;rsquo;s because Java isn&amp;rsquo;t - the hate just extends from the language to its runtime, which is unfortunate.
But there are lots of languages that run on the JVM, and I think it&amp;rsquo;s a good thing and what any system should aim at if it wants to succeed.&lt;/p&gt;
&lt;h3 id=&#34;beam&#34;&gt;BEAM&lt;/h3&gt;
&lt;p&gt;Erlang is another language I think is great, and the VM it runs on is incredible.&lt;/p&gt;
&lt;p&gt;BEAM is a highly dynamic, yet fault-tolerant system with a lot of work dedicated for it to remain stable under high load of tasks.
It was mostly developed for telecom, but it can be used for any scalable backend tasks in general today.&lt;/p&gt;
&lt;p&gt;I would like to mention Prolog here too, although it&amp;rsquo;s a bit unfair, since Erlang pretty much rose from Prolog, but I&amp;rsquo;m just not familiar with Prolog enough.
As a system, it is probably more generic than Erlang, and I like that it has graph querying and manipulating functions in it, as well as many other capabilities.&lt;/p&gt;
&lt;p&gt;One of the main things I like about Erlang&amp;rsquo;s virtual machine is its ability to recover from errors.
As described in the amazing &lt;a href=&#34;https://youtu.be/rRbY3TMUcgQ?t=435&#34; target=&#34;_blank&#34;&gt;Erlang The Movie II: The Sequel&lt;/a&gt; if your code crashes for one of the running threads, none other threads are affected by that.
Then, it&amp;rsquo;s possible to fix the bug, recompile the code, and load it into the running system - fixing the failed thread.
And all other threads will eventually pick the newer version.
How cool is that?&lt;/p&gt;
&lt;h3 id=&#34;lua&#34;&gt;Lua&lt;/h3&gt;
&lt;p&gt;Lua has a really neat and small bytecode VM, and one of the fastest JIT implementations across many similar languages.
As far as I know, this is because of a combination of things.
First, Lua uses a register-based VM, and LuaJIT implemented a tracing JIT for it, basically compiling many Lua register operations into real hardware register operations.
Second, the instruction set of Lua is itself close to machine instructions, making it easier to implement JIT.&lt;/p&gt;
&lt;p&gt;Lua VM itself is very nice and easy to understand - if you have moderate knowledge of C you can probably read and understand the source code of Lua in a weekend.
It&amp;rsquo;s also highly dynamic, and really simple.
There are some downsides to that - inbuilt data structures are not the greatest, and there are some wonky parts about multiple value return.
Other than that, it&amp;rsquo;s very expressive, and you can bend it pretty much however you want.&lt;/p&gt;
&lt;p&gt;One feature of the Lua VM that I absolutely love is its implementation of coroutines.
Functions can be paused, inspected, and resumed at any time, which makes implementing asynchronous programming quite easy.
I&amp;rsquo;ve written a few libraries for pure Lua async, and I think it is beautiful how coroutines provide an elegant solution to this problem.&lt;/p&gt;
&lt;p&gt;Another great feature is that you can &lt;a href=&#34;http://www.lua.org/pil/26.1.html&#34; target=&#34;_blank&#34;&gt;call C functions from Lua&lt;/a&gt;.
FFI is something that many languages do, and I&amp;rsquo;m only talking about it in the context of Lua because that&amp;rsquo;s the only language I&amp;rsquo;ve used it firsthand.&lt;/p&gt;
&lt;p&gt;Lastly, the important thing about Lua is that it can be used both as a standalone VM, and embedded into the application.
Numerous applications embed Lua in different ways to allow scripting and extending the application.
I think it&amp;rsquo;s a good characteristic of the VM, but maybe it isn&amp;rsquo;t a good fit for a programming system.&lt;/p&gt;
&lt;h3 id=&#34;smalltalk&#34;&gt;Smalltalk&lt;/h3&gt;
&lt;p&gt;Finally, Smalltalk.
It&amp;rsquo;s one of the greatest systems, and much like Common Lisp, it is image based.
Unlike Lisp though, you do load an image and work in it, instead of loading the source code.&lt;/p&gt;
&lt;p&gt;Smalltalk is definitively on my list of languages to dive into, but as with Scheme, it is a bit hard to start because of all these different implementations.
I&amp;rsquo;m looking at Glamorous Toolkit, but I&amp;rsquo;m also in fear that it might shatter my love for Emacs.
Probably not, but who knows.&lt;/p&gt;
&lt;p&gt;Anyway, Smalltalk is a very dynamic system, with a lot of introspection capabilities, which I like a lot.
Much like Emacs, because you&amp;rsquo;re interacting with the system directly, a lot of things are possible, and I feel that more systems should allow for that.&lt;/p&gt;
&lt;h3 id=&#34;other-systems&#34;&gt;Other systems&lt;/h3&gt;
&lt;p&gt;You may note that I&amp;rsquo;ve not listed many other systems, like CLR, OCaml, WASM or even Python.
I don&amp;rsquo;t know anything about CLR other than &amp;ldquo;JVM but Microsoft&amp;rdquo;, haven&amp;rsquo;t really tried OCaml, and WASM is too new for me to get into it yet.
And I despise Python as a language, so I just don&amp;rsquo;t wanna bring it to the discussion.&lt;/p&gt;
&lt;p&gt;If you think I should look into any of these systems (except Python) for interesting features - let me know!&lt;/p&gt;
&lt;h2 id=&#34;my-ideal-programming-system&#34;&gt;My ideal Programming System&lt;/h2&gt;
&lt;p&gt;I would try to introduce this term here - a Programming System.
It&amp;rsquo;s not just a language, like, say Python or Lua, instead it is more like Emacs or Smalltalk.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s take the best from all VMs and Systems and compose a list of things I want to see in my dream system.
Note, the list is not about the language features, this will be covered separately in the future (maybe).
I will mark each point with the list of systems that I think handle this well.&lt;/p&gt;
&lt;p&gt;Now, in no particular order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Garbage Collection (JVM, Lisp, Smalltalk, BEAM)&lt;/p&gt;
&lt;p&gt;Duh.&lt;/p&gt;
&lt;p&gt;In all seriousness though, being able to write code without thinking about memory much is one of the reasons why VMs became popular, so I feel that garbage collection is a huge benefit.
There are many approaches for garbage collection, and JVM continues to improve them even in situations where &lt;a href=&#34;https://docs.oracle.com/en/java/javase/11/gctuning/z-garbage-collector1.html&#34; target=&#34;_blank&#34;&gt;heaps are measured in terabytes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Manual memory management should be possible still, for implementing low level stuff, as there are clear benefits to that approach, and thus the system should be able to mix both approaches seamlessly.
Maybe even go as far as allowing to say something like - I&amp;rsquo;ve acquired these resources myself, but due to the circumstances I don&amp;rsquo;t care about them anymore, you&amp;rsquo;re free to collect them in any manner.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynamism all the way down (JVM, Lisp, Smalltalk)&lt;/p&gt;
&lt;p&gt;I see no reason for the system itself to require static typing.
Look at JVM - Java does static typing.
Kotlin does it too.
Scala really does it.
Yet JVM itself is dynamic and everyone is still happy.&lt;/p&gt;
&lt;p&gt;Static types should be only a language-level feature, not system-level.
The system itself should be dynamic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynamic updating mechanism (BEAM, Lisp)&lt;/p&gt;
&lt;p&gt;It should be possible to load code into an already running system without requiring restarting or stopping the system.
This includes extending the program with new features while it is running, adding dependencies as you work, re-loading code, and graceful error handling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Image storing and loading capabilities (Smalltalk, Lisp)&lt;/p&gt;
&lt;p&gt;The ability to dump your whole running system to disk and then resume it, maybe even on a different machine, is one of the greatest features a system can have.
It allows for much better debugging, being able to re-re-run things as you need to, and experiment.&lt;/p&gt;
&lt;p&gt;This feature actually has more purposes than just being able to store state and resume from it.
Being able to take a single thread and write it to the disk to resume it later means we can make snapshots of every worker in the system and restore them even if we get a power outage, for example.
There are &lt;a href=&#34;https://www.golem.cloud/post/what-is-durable-computing&#34; target=&#34;_blank&#34;&gt;projects that do that&lt;/a&gt;, but without an explicit support from the platform it may not always be robust or could come with a lot of additional costs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fast primitive data structures (JVM)&lt;/p&gt;
&lt;p&gt;The system should provide non-resizeable tuples (arrays), (preferably) immutable (and maybe interned) strings, and records.
It should also provide a way to be able to destructure these data structures fast, like unpacking an array onto a stack, but we&amp;rsquo;ll talk about this later.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think classes should be on that low level, though.
Classes are just like records, except with some additional semantics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lightweight threads/Coroutines/Continuations (BEAM, Lua, Scheme, recently JVM)&lt;/p&gt;
&lt;p&gt;In our modern world, asynchronous programming is a must for a system to be viable.
Properly utilizing a single core, and allowing for horizontal scaling, is important for lots of scenarios.
Be it a particle simulation, or a web server handling millions of requests, the system should have a robust mechanism for that.&lt;/p&gt;
&lt;p&gt;There are multiple ways of doing this, each with upsides and downsides, my personal favorite is stackful coroutines, but your opinion may vary.
First-class continuations are another way of achieving it, and perhaps a bit more bare than coroutines.&lt;/p&gt;
&lt;p&gt;I should also include asynchronous IO here, but it is largely system-dependent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multi-threading (JVM)&lt;/p&gt;
&lt;p&gt;Just as important is to be able to utilize multiple cores.
Maybe even tip into GPU utilization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Access to vector instructions and multimedia instructions (SIMD)&lt;/p&gt;
&lt;p&gt;Another big performance gain, pretty much required today by many algorithms.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JIT compilation (Lisp, JVM, LuaJIT)&lt;/p&gt;
&lt;p&gt;If possible, the system should compile everything to machine code, like Common Lisp implementations such as SBCL do.
However, JIT compilation can also be a good compromise, as I imagine it is easier to just port the bytecode interpreter to some new architecture first, and add JIT later, rather than implement a compiler for it from the start.
I like this property of Common Lisp, and it certainly makes things run faster, but even pure bytecode interpreters can achieve good performance if implemented correctly, and with JIT they often have comparable speed to native code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backward compatibility (JVM)&lt;/p&gt;
&lt;p&gt;No bytecode operations should change their meaning, or be removed.
If that&amp;rsquo;s not the case, implementing a compiler to bytecode (or other kind of IR) is a no-go for other languages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FFI (Lua, JVM)&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s hard to ignore the outside world, even if you&amp;rsquo;re making your own world for programs to live in.
Talking to sockets, implementing efficient modules or simply extracting the language with new data structures is important, and isn&amp;rsquo;t often possible to do in the VM-native way.
Many VMs feature FFI for calling C, and in this regard, I have nothing to say that maybe C is not the best choice for that, but we&amp;rsquo;re pretty much stuck with it.
Maybe &lt;a href=&#34;https://ziglang.org&#34; target=&#34;_blank&#34;&gt;Zig&lt;/a&gt; FFI would be better?
We&amp;rsquo;ll see.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Optimized message passing (???)&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think there&amp;rsquo;s a system that can do it yet, or at least I haven&amp;rsquo;t heard of one.
Similarly to Lisp&amp;rsquo;s images, I think it is an interesting idea to explore - using images for message passing.
Maybe BEAM does it, I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;When you need to send a message to another thread it is easy, you just share it via the memory, or just do a copy.
Which of course produces all kinds of interesting problems with shared state.
When you need to send a message to another process, however, it often involves serialization and deserialization, and it is largely a waste because ultimately serialization is only needed to send the data over the wire.
Additionally, it creates barriers on what is ultimately possible.
E.g. you can send functions over the wire, if your runtime supports dynamic evaluation of code, and you can somehow serialize functions, but you can&amp;rsquo;t really send a function that has a closure - because there&amp;rsquo;s no way to serialize it properly.&lt;/p&gt;
&lt;p&gt;So instead, what if we were to send the actual memory blob to the process, and it would map it directly onto its own memory?
I&amp;rsquo;m not sure if this is possible, but if it is, it would allow to actually skip serialization and start sending objects around without a cost of a string parsing and evaluation.
And it would also mean, that if someone to implement object memory layout in other language they would be able to send objects to such system directly as well.
Sounds kind of like a binary protocol, I guess, but for memory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a feature set of a VM I think I would pick when implementing one.
I know there were a lot of text, so let&amp;rsquo;s wrap it up in a shorter list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Register-based VM with small instruction set, and stable bytecode.
&lt;ul&gt;
&lt;li&gt;Maybe use a compiler-tower approach.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Support for different garbage collection strategies.&lt;/li&gt;
&lt;li&gt;Dynamic module and code loading support.&lt;/li&gt;
&lt;li&gt;Image (re)storing capabilities.&lt;/li&gt;
&lt;li&gt;Multi-threading capabilities and stackful coroutines.&lt;/li&gt;
&lt;li&gt;JIT/Compilation to native code.&lt;/li&gt;
&lt;li&gt;Access to vector instructions of the underlying machine with JIT.&lt;/li&gt;
&lt;li&gt;FFI.&lt;/li&gt;
&lt;li&gt;Fast primitive data structures to build upon.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would like to list the last two in a separate list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Embeddability - not as high of a priority, but nice to have and helps keeping project small enough.&lt;/li&gt;
&lt;li&gt;Optimized message passing - needs lots of researching.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we put this into a table, we can actually see what Systems that I&amp;rsquo;ve mentioned match my criteria:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;hr style=&#34;margin: 0;border-top: 1px solid #444;&#34;&gt;Feature&lt;/th&gt;
&lt;th&gt;Guile&lt;/th&gt;
&lt;th&gt;SBCL (Lisp)&lt;/th&gt;
&lt;th&gt;Emacs&lt;/th&gt;
&lt;th&gt;JVM&lt;/th&gt;
&lt;th&gt;Pharo (Smalltalk)&lt;/th&gt;
&lt;th&gt;Lua&lt;/th&gt;
&lt;th&gt;BEAM (Erlang)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Register-based VM&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stable bytecode&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(compiler tower)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❓&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❓&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Different garbage collection strategies&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(since 5.4)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic module and code loading&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image (re)storing&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-threading&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❓&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stackful coroutines (or others)&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;Continuations&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;Virtual Threads&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;Coroutines&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;Processes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JIT/Compilation to native code&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access to vector instructions&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❓&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FFI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fast primitive data structures&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❓&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;hr style=&#34;margin: 0;border-top: 1px solid #444;&#34;&gt;Feature (Optional)&lt;/th&gt;
&lt;th&gt;Guile&lt;/th&gt;
&lt;th&gt;SBCL (Lisp)&lt;/th&gt;
&lt;th&gt;JVM&lt;/th&gt;
&lt;th&gt;Pharo (Smalltalk)&lt;/th&gt;
&lt;th&gt;Lua&lt;/th&gt;
&lt;th&gt;BEAM (Erlang)&lt;/th&gt;
&lt;th&gt;Emacs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embeddability&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimized message passing&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❓&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❓ - I don&amp;rsquo;t know, or couldn&amp;rsquo;t find any info;&lt;/li&gt;
&lt;li&gt;❌ - not supported (doesn&amp;rsquo;t always mean bad, though);&lt;/li&gt;
&lt;li&gt;✅ - supported in one way or another.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, again, if I got anything of this wrong, which I probably did, reach me, and I&amp;rsquo;ll change that.
Same if you know about any cells marked with ❓.&lt;/p&gt;
&lt;p&gt;Additionally, if you think that I should have picked a different implementation of some of these systems, like Chez instead of Guile, or Squeak instead of Pharo, feel free to send me info on them, and I&amp;rsquo;ll include those to the table.
Obviously, I can&amp;rsquo;t research all of them.&lt;/p&gt;
&lt;h2 id=&#34;ideal-programming-system&#34;&gt;Ideal Programming System&lt;/h2&gt;
&lt;p&gt;I know, it is impossible to implement a perfect system.
But if you look at the chart, some are actually extremely close to that, at least in my view.
In particular, Guile, JVM and BEAM are great.&lt;/p&gt;
&lt;p&gt;And despite the fact that Emacs has a lot more ❌ than others, it&amp;rsquo;s still a better programming system than many.
Smalltalk is also a better programming system than many - because it was built to be a programmable system, much like Emacs.
So is the chart flawed?&lt;/p&gt;
&lt;p&gt;Well, yes and no.
It&amp;rsquo;s just more complicated than that, as I hope I&amp;rsquo;ve shown before the chart when I was talking about benefits of each system.
Some do some things better than others.
Emacs isn&amp;rsquo;t a JVM, yet it managed an airport once.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another problem, though.
Software today is a hot topic, and many new languages are created every year.
Most of these languages are just rehashing of existing ones, with some small changes, and almost no actual improvements.
The same can&amp;rsquo;t be said for VMs, but many such languages feature their own VM, like for example &lt;a href=&#34;https://janet-lang.org/&#34; target=&#34;_blank&#34;&gt;Janet&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Occasionally, there are projects like Clojure, where the author with a great experience looked on programming, figured out what problems are currently unsolved, and tried to solve them.
The result is one of the best languages I&amp;rsquo;ve personally used.
Running on one of the best virtual machines.
Sure, it can probably be done better, there are still a lot of hiccups here and there, but it is an improvement over what we had, especially for 2010s.&lt;/p&gt;
&lt;p&gt;And while I&amp;rsquo;m a bit skeptical on this, but in the eyes of many, Elixir is another one such case.
Taking a great technology of BEAM and implementing a friendlier version of Erlang is a huge step-up for many programmers who don&amp;rsquo;t want to work with Prolog-like syntax.&lt;/p&gt;
&lt;p&gt;Then again, projects like Zig feel like a major improvement on what we have in C, so it&amp;rsquo;s not like I&amp;rsquo;m saying that people should stop working on new languages and platforms.
I&amp;rsquo;m just saying that there should be enough of improvements on real problems.&lt;/p&gt;
&lt;p&gt;Am I listing real problems, though?
I would say yes but, really, I don&amp;rsquo;t know.
For me, all capabilities I&amp;rsquo;ve listed would prove useful in my work - JVM&amp;rsquo;s lack of coroutines (I use older JVM) or image (re)storing is often a problem for me.
SIMD is needed less often, but I really wouldn&amp;rsquo;t mind it, because it can be used to substantially speed up regular expression engines, or parsers.
Register-based VM isn&amp;rsquo;t a hard requirement, as long as VM is fast, and JVM is, so it&amp;rsquo;s not big of a deal here.
Though JVM is not exactly a programming system either.
Then again, if I were to work in Lisp or Smalltalk, then I probably would have another set of complaints - so there&amp;rsquo;s probably no definitive answer to the question.&lt;/p&gt;
&lt;p&gt;Would I work on such a programming system myself?
Probably yes, but I&amp;rsquo;m far from it knowledge-wise.
Again, I&amp;rsquo;ve read some books on the topic, but I need to learn much more.
Perhaps I should take a compiler course too.
It is a very hard area of programming, and probably people who are knowledgeable in this are offended by this article, so sorry for that!&lt;/p&gt;
&lt;p&gt;Currently, I&amp;rsquo;m working through the second part of the Crafting Interpreters book in Zig.
It is an interesting book, when I was researching the topic it felt like a good entry point to the field.
Perhaps a dragon book should be next?
Let me know if you have good literature recommendations on the matter, it&amp;rsquo;s always appreciated.&lt;/p&gt;
&lt;p&gt;Anyhow, I hope this was entertaining.
Thank you for reading!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;AFAIK Janet was born because the author was fed up with Lua VM, and the Fennel project could not give them what they wanted.
So Janet was created.
However, there&amp;rsquo;s no JIT in Janet, and VM isn&amp;rsquo;t much different from what I have seen, so was it really worth to make another Lua-like VM but not improve it enough?
I have a lot of complaints about Janet, but it&amp;rsquo;s not my project, so it&amp;rsquo;s not my problem, and who am I to even criticize it.
They&amp;rsquo;re doing what they want to do, and that&amp;rsquo;s great.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: A programming system&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 18 Oct 2023 22:56:00 +0300</pubDate>
    </item><item>
      <title>Compiling Clojure projects in Emacs - Jumping into dependencies</title>
      <link>https://andreyor.st/posts/2023-10-03-compiling-clojure-projects-in-emacs-jumping-into-dependencies/</link>
      <guid>https://andreyor.st/posts/2023-10-03-compiling-clojure-projects-in-emacs-jumping-into-dependencies/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://andreyor.st/posts/2023-01-10-compiling-clojure-projects-in-emacs/&#34;&gt;previous post&lt;/a&gt; on the subject I&amp;rsquo;ve described how one can create a custom compilation mode for any language.
In the &lt;a href=&#34;https://andreyor.st/posts/2023-01-10-compiling-clojure-projects-in-emacs/#dynamically-extracting-filenames-from-compiler-output&#34;&gt;Dynamically extracting filenames from compiler output&lt;/a&gt; section I&amp;rsquo;m talking about various issues with how Clojure reports problem locations.
The main problem is when the problem is inside of a dependency, and be it your own library, or a third-party one it&amp;rsquo;s equally tedious to go and look into it because the dependency usually is a &lt;code&gt;jar&lt;/code&gt; file somewhere in the &lt;code&gt;~/.m2&lt;/code&gt; directory.
And the actual problem is that the error message doesn&amp;rsquo;t really tell you what dependency to look into, it just uses a path to the file as if it was a file in a project.
We can always ignore such files, but it&amp;rsquo;s not great, as we&amp;rsquo;re effectively closing our eyes on existing problems in our codebase.&lt;/p&gt;
&lt;p&gt;Since the previous post I&amp;rsquo;ve tweaked the function that gets the filename for the given compilation output line - now it can find files in the project&amp;rsquo;s dependencies as well.
It&amp;rsquo;s still not entirely reliable, as theoretically there might be some name clashes, but I have yet to see any actual problems with this approach.
This approach involves dealing with the &lt;code&gt;classpath&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;updated-define-project-compilation-mode-macro&#34;&gt;Updated &lt;code&gt;define-project-compilation-mode&lt;/code&gt; macro&lt;/h2&gt;
&lt;p&gt;I had to update the macro I&amp;rsquo;m using to generate these helper modes.
The main changes are that the supplementary &lt;code&gt;compile-add-error-syntax&lt;/code&gt; function is now adding a &lt;code&gt;HIGHLIGHT&lt;/code&gt; parameter to the &lt;code&gt;compilation-error-regexp-alist-alist&lt;/code&gt;, and automatically specifies that it should only be applied to the &lt;code&gt;hyperlink&lt;/code&gt; group.
The face is chosen automatically based on the &lt;code&gt;level&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cl-defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;regexp&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;key&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;error&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hyperlink&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;highlight&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Register new compilation error syntax.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Add NAME symbol to &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`compilation-error-regexp-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;, and then add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;REGEXP FILE LINE and optional COL LEVEL info to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`compilation-error-regexp-alist-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (error &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Missing value for :file keyword&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (error &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Missing value for :line keyword&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faces&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-info-face&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-warning-face&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-error-face&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;info&lt;/span&gt;) 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;warn&lt;/span&gt;) 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;error&lt;/span&gt;) 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (error &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Unsupported level type: %S&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;symbol-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;compilation&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-error-regexp-alist&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-error-regexp-alist-alist&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;regexp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;col&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hyperlink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;highlight&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faces&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Changes to the macro itself are quite small:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-project-compilation-mode&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base-name&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;declare&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base-name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;doc-name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;capitalize&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-compilation$&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-root&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-current-project&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-files&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-current-project-files&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-mode-name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-mode&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-error-regexp-alist&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Alist that specifies how to match errors in &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;doc-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; compiler output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;See &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`compilation-error-regexp-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; for more information.&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;intern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-error-regexp-alist-alist&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Alist of values for `&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;downcase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;doc-name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-compilation-error-regexp-alist&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;See &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`compilation-error-regexp-alist-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; for more information.&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar-local&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-root&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Current root of the project being compiled.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Set automatically by the `&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-mode-name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#39;.&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar-local&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-files&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Current list of files belonging to the project being compiled.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Set automatically by the `&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;symbol-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-mode-name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#39;.&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-compilation-mode&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-mode-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;doc-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; Compilation&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Compilation mode for &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;doc-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; output.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-root&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-files&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-files&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-project-root&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ,@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;provide&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;,compilation-mode-name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve moved &lt;code&gt;,@body&lt;/code&gt; inside the call to &lt;code&gt;define-compilation-mode&lt;/code&gt; as it really was a mistake in the previous version of the macro.
This way we can extend the initialization step of the mode with additional expressions in the &lt;code&gt;body&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;working-with-project-s-classpath&#34;&gt;Working with project&amp;rsquo;s &lt;code&gt;classpath&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;First things first, we need to query our project for &lt;code&gt;classpath&lt;/code&gt;.
It can be done with &lt;code&gt;lein classpath&lt;/code&gt; or &lt;code&gt;clojure -Spath&lt;/code&gt; if you&amp;rsquo;re using &lt;code&gt;deps&lt;/code&gt;.
For this post, I&amp;rsquo;m going to continue with &lt;code&gt;lein&lt;/code&gt;, as it is what I use at work, and I&amp;rsquo;m unfamiliar with most &lt;code&gt;deps&lt;/code&gt; commands, i.e. for example, I don&amp;rsquo;t know what the analog to &lt;code&gt;lein check&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code below defines some functions that in the end will return a list of strings.
These strings are paths to &lt;code&gt;.jar&lt;/code&gt; archives being used by our project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--split-classpath&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;classpath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Split the CLASSPATH string.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;split-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;classpath&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[[:space:]\n]+&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-project-dependencies*&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_deps-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_mod-time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Call COMMAND to obtain the classpath string.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;DEPS-FILE and MOD-TIME are used for memoization.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shell-command-to-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--split-classpath&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-suffix-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.jar&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation--get-project-dependencies-memo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memoize&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-project-dependencies*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-lein-project-dependencies&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Obtain classpath from lein for ROOT.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;project.clj&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-attribute-modification-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-attributes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-file&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-project-dependencies-memo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lein classpath&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod-time&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-deps-project-dependencies&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Obtain classpath from deps for ROOT.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;deps.edn&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-attribute-modification-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-attributes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-file&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-project-dependencies-memo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;clojure -Spath&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod-time&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-get-project-dependencies&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Get dependencies of the given PROJECT.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Returns a list of all jar archives.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tramp-gvfs-enabled&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-exists-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;deps.edn&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-deps-project-dependencies&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-exists-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;project.clj&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--get-lein-project-dependencies&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using the &lt;code&gt;define-project-compilation-mode&lt;/code&gt; macro that I&amp;rsquo;ve defined above we can create a &lt;code&gt;clojure-compilation-mode&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;List of project&amp;#39;s dependencies&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps-mod-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Accumulated modification time of all project&amp;#39;s libraries&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;define-project-compilation-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;tramp-gvfs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-get-project-dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-current-project&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps-mod-time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq-reduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;+&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapcar&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time-to-seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-attribute-modification-time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-attributes&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          0)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Upon initializing, it will query &lt;code&gt;lein&lt;/code&gt; (or &lt;code&gt;deps&lt;/code&gt;) for the project&amp;rsquo;s classpath, and store it in the &lt;code&gt;clojure-compilation-project-deps&lt;/code&gt; var.
In addition to that we store the accumulated modification time of all of our dependencies.
Spinning up &lt;code&gt;lein classpath&lt;/code&gt; every time project is re-compiled is quite slow, and we only really need to do it when &lt;code&gt;project.clj&lt;/code&gt; was recently changed, so I&amp;rsquo;m using a simple memoization function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memoize&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Create a storage for FN&amp;#39;s args.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Checks if FN was called with set args before.  If so, return the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;value from the storage and don&amp;#39;t call FN.  Otherwise calls FN,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;and saves its result in the storage.  FN must be referentially
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;transparent.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memo&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-hash-table&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:test&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;equal&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethash&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memo&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puthash&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memo&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We memoize the call to &lt;code&gt;clojure-compilation--get-project-dependencies*&lt;/code&gt; by its &lt;code&gt;command&lt;/code&gt;, &lt;code&gt;filename&lt;/code&gt;, and the file&amp;rsquo;s modification timestamp.
So, if the filename or timestamp changes, we re-compute the dependencies.
Now we look at the function that is used in the &lt;code&gt;compilation-error-regexp-alist-alist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But before that, let&amp;rsquo;s define some rules:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;some-warning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^\\([^:[:space:]]+\\):\\([0-9]+\\) &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;warn&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clj-kondo-warning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^\\(/[^:]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\): warning&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:col&lt;/span&gt; 3 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;warn&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clj-kondo-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^\\(/[^:]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\): error&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:col&lt;/span&gt; 3 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;kaocha-tap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^not ok.*(\\([^:]*\\):\\([0-9]*\\))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-fail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^.*\\(?:FAIL\\|ERROR\\) in.*(\\([^:]*\\):\\([0-9]*\\))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-reflection-warning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^Reflection warning,[[:space:]]*\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:col&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;warn&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-performance-warning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^Performance warning,[[:space:]]*\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:col&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;warn&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-syntax-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^Syntax error .* at (\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:col&lt;/span&gt; 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;kaocha-unit-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^ERROR in unit (\\([^:]+\\):\\([0-9]+\\))&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile-add-error-syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;eastwood-warning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^\\([^:[:space:]]+\\):\\([0-9]+\\):\\([0-9]+\\):&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:line&lt;/span&gt; 2 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:col&lt;/span&gt; 3 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:level&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;warn&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hyperlink&lt;/span&gt; 1 &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:highlight&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These are the rules I&amp;rsquo;m using at work, it&amp;rsquo;s quite handy to be able to jump from the compilation buffer and see if the problem is fixable.
The &lt;code&gt;clojure-compilation-filename&lt;/code&gt; is defined as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Function that gets filename from the error message.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;If the filename comes from a dependency, try to guess the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;dependency artifact based on the project&amp;#39;s dependencies.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-string&lt;/span&gt; 1))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-file-in-project&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dep&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-dep&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dep&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It splits the task into two parts.
First, it checks if the file is part of the project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-file-in-project&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Check if FILE is part of the currently compiled project.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq-find&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-suffix-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-current-project-files&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a rather simple filter of the &lt;code&gt;clojure-compilation-current-project-files&lt;/code&gt; var we create when the &lt;code&gt;clojure-compilation-mode&lt;/code&gt; starts.&lt;/p&gt;
&lt;p&gt;The second part is similar, but it tries to find a matching dependency.
Unfortunately, knowing the file name doesn&amp;rsquo;t mean that we&amp;rsquo;ll be able to find the dependency itself, as the artifact name may not have the same name.
But this is somewhat rare, so we can do it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--file-exists-jar-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Check if FILE is present in the JAR archive.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-temp-buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zerop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;call-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;jar&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-tf&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jar&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-match-data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;re-search-forward&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^%s$&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;regexp-quote&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-dep*&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_project&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_deps-mod-time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Find FILE in current project dependency list.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;PROJECT and DEPS-MOD-TIME are used for memoizing the call.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq-find&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--file-exists-jar-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fset&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation--find-dep-memo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memoize&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-dep*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-dep&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Find FILE in current project dependency list.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-dep-memo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-current-project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-deps-mod-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot going on, but the idea is basically the same as for the project&amp;rsquo;s dependencies.
We memoize &lt;code&gt;clojure-compilation--find-dep*&lt;/code&gt; by the &lt;code&gt;file&lt;/code&gt;, current project, and accumulated modification time of all dependencies.
If any of the dependencies changes we&amp;rsquo;ll re-compute the whole thing.
Otherwise, if the &lt;code&gt;file&lt;/code&gt; is present multiple times in the compilation output we will avoid searching for it multiple times thanks to the memoization.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s a log from &lt;code&gt;lein check&lt;/code&gt;.
I have omitted any lines that are related to the project itself, so we&amp;rsquo;re only looking at warnings inside the dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-*- mode: clojure-compilation; default-directory: &amp;#34;~/some/project/&amp;#34; -*-
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Clojure Compilation started at Mon Oct  2 15:29:30
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lein do clean, check
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, me/raynes/fs.clj:517:42 - reference to field getName can&amp;#39;t be resolved.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, clojure/data/xml.clj:337:17 - call to method createXMLStreamReader can&amp;#39;t be resolved (target class is unknown).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, instaparse/util.clj:5:3 - call to java.lang.RuntimeException ctor can&amp;#39;t be resolved.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, instaparse/util.clj:11:3 - call to java.lang.IllegalArgumentException ctor can&amp;#39;t be resolved.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, ring/util/servlet.clj:88:24 - call to method write on javax.servlet.ServletOutputStream can&amp;#39;t be resolved (argument types: unknown).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, given a &lt;code&gt;filename&lt;/code&gt; of &lt;code&gt;me/raynes/fs.clj&lt;/code&gt; and a dependency list like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/org/clojure/data.xml/0.0.8/data.xml-0.0.8.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/instaparse/instaparse/1.4.8/instaparse-1.4.8.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/me/raynes/fs/1.4.6/fs-1.4.6.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/ch/qos/logback/logback-core/1.2.11/logback-core-1.2.11.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/ring-logger/ring-logger/1.1.1/ring-logger-1.1.1.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/ring/ring-servlet/1.10.0/ring-servlet-1.10.0.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/.m2/repository/ring/ring-core/1.10.0/ring-core-1.10.0.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ...)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because &lt;code&gt;me/raynes/fs.clj&lt;/code&gt; is not part of the project, we will have to go through every &lt;code&gt;.jar&lt;/code&gt; archive, get its file listing, and check if any have this file.
I&amp;rsquo;m not sure if it is possible for two archives in the classpath list to have the same file, and that never happened to me yet, so I assume it is a reliable enough way of doing this.
Thus, the result of &lt;code&gt;clojure-compilation-filename&lt;/code&gt; will be &lt;code&gt;&amp;quot;~/.m2/repository/me/raynes/fs/1.4.6/fs-1.4.6.jar/me/raynes/fs.clj&amp;quot;&lt;/code&gt;.
But what should we do with it?&lt;/p&gt;
&lt;p&gt;Emacs actually can open this kind of path with TRAMP if the &lt;code&gt;gvfs&lt;/code&gt; is present on the system, hence the check in the &lt;code&gt;clojure-compilation-get-project-dependencies&lt;/code&gt; function.
If &lt;code&gt;gvfs&lt;/code&gt; is not available there&amp;rsquo;s no point in analyzing dependencies, because, without it, Emacs can&amp;rsquo;t go inside such an archive.
And I&amp;rsquo;m not sure why - Emacs can open archives much like DIRED opens directories, and then we can open files from these archives, it just has to be done in two steps and there&amp;rsquo;s no special path syntax to open an archive, and jump to a file immediately.
With &lt;code&gt;gvfs&lt;/code&gt; however, Emacs can mount the archive, and jump to the &lt;code&gt;me/raynes/fs.clj&lt;/code&gt; file inside of it in one go, thus highlighting the problem in the dependency:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;find-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Find files matching given pattern.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex; background-color:#e5e5e5&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;find-files*&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;path &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;re-matches &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pattern&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getName&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  warning in the &lt;code&gt;~/.m2/repository/me/raynes/fs/1.4.6/fs-1.4.6.jar/me/raynes/fs.clj&lt;/code&gt; file.
&lt;/div&gt;
&lt;p&gt;The only downside of this approach is that, for some reason, Emacs takes a very long time to unmount these archives when I close it.
This has nothing to do with the method, and probably an issue with the &lt;code&gt;gvfs&lt;/code&gt; support in general.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;gvfs&lt;/code&gt; package isn&amp;rsquo;t available it&amp;rsquo;s probably possible to use the &lt;a href=&#34;https://elpa.gnu.org/packages/jarchive.html&#34; target=&#34;_blank&#34;&gt;jarchive&lt;/a&gt; package, however, the filename format returned by the &lt;code&gt;clojure-compilation-filename&lt;/code&gt; function has to be changed to include the &lt;code&gt;jar:file://&lt;/code&gt; scheme and use &lt;code&gt;!&lt;/code&gt; as a separator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dep&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation--find-dep&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;jar:file://&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dep&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;!&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Though, unfortunately, I couldn&amp;rsquo;t make it work with &lt;code&gt;jarchive&lt;/code&gt; because for some reason Emacs transforms &lt;code&gt;jar:file:///foo/bar&lt;/code&gt; to &lt;code&gt;jar:file:/foo/bar&lt;/code&gt; right before a file is opened, and &lt;code&gt;jarchive&lt;/code&gt; specifically looks for &lt;code&gt;jar:file:///&lt;/code&gt; as a prefix.
Maybe there&amp;rsquo;s some kind of a setting for that.
If you know about such, let me know too!&lt;/p&gt;
&lt;p&gt;With all in place, Clojure warnings are fully intractable from the compilation buffer.
Even though Clojure is a language where we rarely use edit-compile-check cycle, I find it tremendously useful to be able to call &lt;code&gt;lein check&lt;/code&gt;, and other tools like &lt;a href=&#34;https://github.com/clj-kondo/clj-kondo&#34; target=&#34;_blank&#34;&gt;clj-kondo&lt;/a&gt; or &lt;a href=&#34;https://github.com/jonase/eastwood&#34; target=&#34;_blank&#34;&gt;eastwood&lt;/a&gt;.
Same with the &lt;a href=&#34;https://github.com/lambdaisland/kaocha&#34; target=&#34;_blank&#34;&gt;kaocha&lt;/a&gt; test runner.&lt;/p&gt;
&lt;p&gt;Emacs is very configurable.
I would say that the &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; isn&amp;rsquo;t the most straightforward interface for configuring how errors are parsed, but it gets the job done and is very versatile.
It&amp;rsquo;s a general pattern in Emacs, many such configurations accept functions in arbitrary places, allowing users to extend the interface even more than it is possible with just regular parameters.
Because of that Emacs is also an infinite time sink, and seeing how my configuration grows by the day even after using Emacs for many years is both inspiring and scary.
Inspiring because Emacs shows that such a configurable system is possible.
Scary because I don&amp;rsquo;t know if the process will ever stop.&lt;/p&gt;
&lt;p&gt;I hope this post was useful, and gave you the idea of how you can create custom handlers for the compilation buffer.
The whole configuration for Clojure can be found &lt;a href=&#34;https://github.com/andreyorst/dotfiles/blob/6d50c0abb135b0cd540ed26d9dc0589c52455615/.config/emacs/init.el#L1717-L1908&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.
Macros for defining language compilation modes are &lt;a href=&#34;https://github.com/andreyorst/dotfiles/blob/76f92d973331e2a7e33c0335488f0b3239069dcb/.config/emacs/init.el#L1717-L1771&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.
The required advice for the &lt;code&gt;compilation-start&lt;/code&gt; function is available &lt;a href=&#34;https://github.com/andreyorst/dotfiles/blob/6d50c0abb135b0cd540ed26d9dc0589c52455615/.config/emacs/init.el#L1616-L1623&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.
Let me know if you had any problems with this code, or have ideas on any possible improvements!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Compiling Clojure projects in Emacs - Jumping into dependencies&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 03 Oct 2023 21:35:00 +0300</pubDate>
    </item><item>
      <title>Game3 - Results</title>
      <link>https://andreyor.st/posts/2023-10-01-game3-results/</link>
      <guid>https://andreyor.st/posts/2023-10-01-game3-results/</guid>
      <description>&lt;p&gt;I gave myself 1 extra day on this game because in total I was only able to work on this game for 5 days, two of which were on the train.
So this game is now done, although I couldn&amp;rsquo;t make any sounds for it.
Designing explosion and blaster sounds that sound good is hard.
The game isn&amp;rsquo;t really complete, and you get practically invincible once you get 3 power-ups.
As wasn&amp;rsquo;t able to do much this time, so a lot of sprites are left unused.
Anyhow, here&amp;rsquo;s the game:&lt;/p&gt;
&lt;iframe src=&#34;https://itch.io/embed-upload/8798744?color=3e3c57&#34;
        allowfullscreen=&#34;&#34;
        width=&#34;600&#34;
        height=&#34;320&#34;
        frameborder=&#34;0&#34;
        style=&#34;margin-left: auto; margin-right: auto; display: block;&#34;&gt;
  &lt;a href=&#34;https://andreyorst.itch.io/game3-shoot-em-up&#34;&gt;Play Game3 - Shoot &#39;Em Up on itch.io&lt;/a&gt;
&lt;/iframe&gt;
&lt;p&gt;Since the last post, I changed a lot.
First, &lt;code&gt;bump&lt;/code&gt; is back and all collisions are handled through it again.&lt;/p&gt;
&lt;p&gt;I made some more weapons, the default one has a rapid-fire rate, but low damage:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-10-01-game3-results/game.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;There are three more weapons - laser gun, magic gun, and rocket gun.
Each of these has different damage values.
Originally I planned to implement the overheat mechanic, but ran out of time and passion to do that.&lt;/p&gt;
&lt;p&gt;It was fun implementing the flame that appears when the ship is taken down.
It is done as a particle effect, as the ship simply constantly emits flame particles when burning, and they get removed once their animation ends.
Similar to how the bullets interact with enemies.&lt;/p&gt;
&lt;p&gt;If you want to download this game, here&amp;rsquo;s the cartridge:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-10-01-game3-results/cart.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The next game on my list is a puzzle platformer.
For now, I&amp;rsquo;m not sure if I will have time or passion to do it, and I honestly don&amp;rsquo;t know what types of puzzles should it have.
We&amp;rsquo;ll see.
I already have a pretty decent engine for a platforming game, so it&amp;rsquo;s a good time to refine it.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game3 - Results&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 01 Oct 2023 17:12:00 +0300</pubDate>
    </item><item>
      <title>Iterator-based transducers in Lua</title>
      <link>https://andreyor.st/posts/2023-09-26-iterator-based-transducers-in-lua/</link>
      <guid>https://andreyor.st/posts/2023-09-26-iterator-based-transducers-in-lua/</guid>
      <description>&lt;p&gt;Early on in my career, when I saw a function that returns an anonymous function, I felt a weird mix of emotions.
It was just a weird thing to do, especially when you&amp;rsquo;re coming from C, where there are no anonymous functions.
Such concepts as lambdas in C++ were hard to grasp, and I&amp;rsquo;m thankful that instead of continuing to hit my head against the C++ wall I picked Scheme, and it helped me understand many core concepts, such as higher-order functions that we&amp;rsquo;ll be mainly talking about in this post.
Today, when I see functions returning functions I understand what happens and feel comfortable.
But not so long ago, functions returning functions returning functions were still alienating to me, at least a bit.&lt;/p&gt;
&lt;p&gt;After I tackled transducers and tried to explain them in a &lt;a href=&#34;https://andreyor.st/posts/2022-08-13-understanding-transducers/&#34;&gt;post&lt;/a&gt;, I became much more comfortable with all these stacked-up anonymous functions.
Clojure, actually spices things up with arity overloading, so understanding transducers is even harder there, as different arities serve as different stages.&lt;/p&gt;
&lt;p&gt;In this post, I would like to share with you some tricks with Lua iterators.
I already have a &lt;a href=&#34;https://andreyor.st/posts/2021-10-09-lazy-sequences-and-iterators/&#34;&gt;post&lt;/a&gt; on differences between iterators and lazy sequences, so to keep things brief, here&amp;rsquo;s a short explanation of how iterators work in Lua.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Iterators in Lua mostly are stateless functions that accept an object, let&amp;rsquo;s call it &lt;code&gt;iterable&lt;/code&gt;, and a &lt;code&gt;key&lt;/code&gt;, and somehow produce the next key and a value associated with it, if any.&lt;/li&gt;
&lt;li&gt;Stateful iterators usually skip the &lt;code&gt;key&lt;/code&gt; part and work with the &lt;code&gt;iterable&lt;/code&gt; object alone, keeping the state somewhere in a closure, or inside the object itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So an iterator in Lua is actually a set of values - the function to produce the next &lt;code&gt;key&lt;/code&gt;, an object to iterate on, and some initial value.
But you don&amp;rsquo;t have to write this manually, although you can, Lua has functions that produce iterators for a given object.
For example, &lt;code&gt;pairs&lt;/code&gt; is such a function, it returns the function &lt;code&gt;next&lt;/code&gt; (the actual iterator), the &lt;code&gt;iterable&lt;/code&gt; object, and initial &lt;code&gt;key&lt;/code&gt; to start the iteration.&lt;/p&gt;
&lt;p&gt;Working with such iterators is done with the &lt;code&gt;for&lt;/code&gt; loop, by providing it an &lt;code&gt;in&lt;/code&gt; keyword.
When you say &lt;code&gt;for k,v in pairs(obj) do ... end&lt;/code&gt; in Lua, &lt;code&gt;pairs&lt;/code&gt; returns the &lt;code&gt;next&lt;/code&gt; function, the &lt;code&gt;obj&lt;/code&gt; and the first &lt;code&gt;key&lt;/code&gt; in &lt;code&gt;obj&lt;/code&gt; to the &lt;code&gt;for&lt;/code&gt; loop, and subsequently calls &lt;code&gt;next(obj, k)&lt;/code&gt; for each &lt;code&gt;k&lt;/code&gt;.
And, you can actually say &lt;code&gt;for k,v in next,obj,nil do ... end&lt;/code&gt; and it will work the same way because that&amp;rsquo;s what &lt;code&gt;pairs&lt;/code&gt; will return.&lt;/p&gt;
&lt;p&gt;Now that we&amp;rsquo;ve covered iterators, let&amp;rsquo;s play with them!&lt;/p&gt;
&lt;p&gt;What I like about Clojure&amp;rsquo;s transducers, is that it is possible to create a data pipeline, abstract from how the data comes to you and where you should put it to.
A transducer is first given the instructions, on how to handle incoming data, then it is given the means &lt;strong&gt;how&lt;/strong&gt; to put it &lt;em&gt;somewhere&lt;/em&gt;.
We&amp;rsquo;ll be skipping the &lt;strong&gt;how&lt;/strong&gt; part here because in Lua there&amp;rsquo;s no standard interface for how to put things into an object.
Depending on the data, you&amp;rsquo;ll either use &lt;code&gt;table.insert&lt;/code&gt;, set the value with the &lt;code&gt;obj[key]=value&lt;/code&gt; syntax, or use a method provided by the object.
So instead, we&amp;rsquo;ll reuse the &lt;code&gt;for&lt;/code&gt; loop here and will rely on it&amp;rsquo;s main interface, as it is the unambiguous way to iterate in Lua.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s create a &lt;code&gt;mapping&lt;/code&gt; transducer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapping&lt;/span&gt;(f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; f1 = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; wrap = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; step = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f1(next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; step, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; wrap(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s ignore the &lt;code&gt;f1&lt;/code&gt; definition for now, and move to the first &lt;code&gt;return&lt;/code&gt; statement straight ahead.
After calling &lt;code&gt;mapping&lt;/code&gt; with some function, the result of this code will itself be a function that accepts an iterator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; wrap = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; step = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f1(next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; step, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; wrap(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This function itself returns an anonymous function that will &lt;code&gt;wrap&lt;/code&gt; the &lt;code&gt;iterator&lt;/code&gt; and sneakily replace its &lt;code&gt;next&lt;/code&gt; function with our own &lt;code&gt;step&lt;/code&gt; function.
Our &lt;code&gt;step&lt;/code&gt; function isn&amp;rsquo;t magic though, it still relies on the &lt;code&gt;next&lt;/code&gt; function from the iterator that we pass into &lt;code&gt;wrap&lt;/code&gt; as &lt;code&gt;next1&lt;/code&gt; to avoid a possible name clash.
You&amp;rsquo;ll never know when it hits you.
The rest of the values stored as &lt;code&gt;...&lt;/code&gt; from the iterator are returned as is.&lt;/p&gt;
&lt;p&gt;As you can see, we&amp;rsquo;re down three anonymous functions already.
Well, &lt;code&gt;wrap&lt;/code&gt; isn&amp;rsquo;t really anonymous, but it&amp;rsquo;s still manipulating other functions.
Let&amp;rsquo;s try this transducer quickly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;inc = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (k, x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; k, x + 1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;incrementing = mapping(inc)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;incrementing_pairs = incrementing(pairs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,x &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; incrementing_pairs {0,1,2} &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s break this down again.&lt;/p&gt;
&lt;p&gt;Here, I&amp;rsquo;ve created the &lt;code&gt;inc&lt;/code&gt; function, which accepts a key, and a value, returns the key as is, and increments the value by &lt;code&gt;1&lt;/code&gt;.
Returning the key is necessary because this function will basically become an iterator later on.
We pass it to &lt;code&gt;mapping&lt;/code&gt; to create a wrapper function for an iterator-producing function, and we call it &lt;code&gt;incrementing&lt;/code&gt;, because it&amp;rsquo;s what this function really does - it is incrementing every value it receives, but it doesn&amp;rsquo;t yet know how to get them.&lt;/p&gt;
&lt;p&gt;This is decided when we pass &lt;code&gt;pairs&lt;/code&gt; to &lt;code&gt;incrementing&lt;/code&gt;, deciding that our function will get all key-value pairs from an object, and map &lt;code&gt;inc&lt;/code&gt; over them.
Alternatively, we could have passed &lt;code&gt;ipairs&lt;/code&gt; and only map &lt;code&gt;inc&lt;/code&gt; over the sequential part of the table.&lt;/p&gt;
&lt;p&gt;Finally, we call &lt;code&gt;incrementing_pairs&lt;/code&gt; with a table, in a &lt;code&gt;for in&lt;/code&gt; loop, and it prints the values from the table incremented by 1.
Alternatively, this can be written as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,x &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; mapping(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (k,x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; k,x+1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(pairs)({0,1,2}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A bit more cramped, but readable.&lt;/p&gt;
&lt;p&gt;And, basically, that&amp;rsquo;s it - now we can write more transducers.
But before we do, let&amp;rsquo;s go back a bit, and understand why I had to wrap &lt;code&gt;f&lt;/code&gt; in &lt;code&gt;f1&lt;/code&gt; right at the beginning of the &lt;code&gt;mapping&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; f1 = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This function is called on each iteration, and iterators terminate the iteration by returning &lt;code&gt;nil&lt;/code&gt; as a key without a value.
So if we got &lt;code&gt;nil&lt;/code&gt; as the first value of the &lt;code&gt;...&lt;/code&gt;, it means that the iteration is ended, and there&amp;rsquo;s no need to call &lt;code&gt;f&lt;/code&gt; anymore.
We can still call &lt;code&gt;f&lt;/code&gt;, but it would mean that &lt;code&gt;f&lt;/code&gt; will have to check if it is the end of the iteration, which isn&amp;rsquo;t great.&lt;/p&gt;
&lt;p&gt;By the way, this works as a general interface, so we can use &lt;code&gt;mapping&lt;/code&gt; with other iterators, like &lt;code&gt;string.gmatch&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;words = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (s) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; s:gmatch(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%w+&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;upcasing = mapping(string.upper)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;upcased_words = upcasing(words)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- one-liner: mapping(string.upper)(function (s) return s:gmatch(&amp;#34;%w+&amp;#34;) end)(&amp;#34;so loud&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; word &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; upcased_words &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;so loud&amp;#34;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(word)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- SO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- LOUD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another interesting property of this approach is that we can compose different functions into a complete data pipeline, abstracting away how they interact:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;upcasing = mapping(string.upper)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reversing = mapping(string.reverse)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; s &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; upcasing(reversing(words))(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- OOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- RAB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can write a helper function, that will compose several functions into a single one, like this &lt;code&gt;f = compose(a, b, c); f(42)&lt;/code&gt; produces the same result as &lt;code&gt;a(b(c(42)))&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compose&lt;/span&gt;(f, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; comp = f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i=1,select(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt;, ...) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; f,g = comp,select(i, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        comp = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(g(...)) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; comp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It can be helpful when we want to create a data pipeline quickly and won&amp;rsquo;t be subject to too much chaining:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; s &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; compose(mapping(string.upper),mapping(string.reverse))(words)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s write a &lt;code&gt;filtering&lt;/code&gt; transducer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filtering&lt;/span&gt;(f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; f1 = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (recur, iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; f(...) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; recur(iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f1(step, iterable, next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; step, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I hope you&amp;rsquo;ll forgive my a bit unconventional formatting here, it&amp;rsquo;s just much easier to read this way for me.
I&amp;rsquo;m putting all &lt;code&gt;end&lt;/code&gt; on the same line and vertically aligning them with all indented blocks, so it&amp;rsquo;s more like Python - when the indentation changes, the scope usually does too.
Mainly, it saves so much vertical space, and this article is already long.
Anyway, This function is even more complicated, so let&amp;rsquo;s break it down too.&lt;/p&gt;
&lt;p&gt;First, you&amp;rsquo;ll notice that the &lt;code&gt;f1&lt;/code&gt; function is different.
Again, we&amp;rsquo;ll ignore it for the time being, and move straight to the function that wraps the &lt;code&gt;iterator&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f1(step, iterable, next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; step, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Same as before, it returns a function, wrapping a call to &lt;code&gt;iterator&lt;/code&gt; to swap its &lt;code&gt;next&lt;/code&gt; function with our &lt;code&gt;step&lt;/code&gt;.
Although, this time around I instead use an &lt;abbr title=&#34;Immediately Executed Function Expression&#34;&gt;IIFE&lt;/abbr&gt; to avoid introducing an explicit wrapper.
The &lt;code&gt;step&lt;/code&gt; function, however, &lt;strong&gt;must&lt;/strong&gt; be a named one, e.g. not &lt;code&gt;local step = function () ...&lt;/code&gt; but &lt;code&gt;local function step () ...&lt;/code&gt;, as it passes itself to &lt;code&gt;f1&lt;/code&gt; along with the object we iterate on, as well as everything from &lt;code&gt;next1&lt;/code&gt;.
We&amp;rsquo;ll get to that shortly.&lt;/p&gt;
&lt;p&gt;Same as with &lt;code&gt;mapping&lt;/code&gt;, we can use &lt;code&gt;filtering&lt;/code&gt; with a function, but now we don&amp;rsquo;t actually need to return a key.
This is because this time &lt;code&gt;f1&lt;/code&gt; check if &lt;code&gt;f&lt;/code&gt; returns a truthy value, and if we were to return a key, it would count as truth:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;is_even = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (_,v) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; v%2==0 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; filtering(is_even)(pairs)({0,1,2,3,4}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As before, we can use &lt;code&gt;compose&lt;/code&gt; to create a data pipeline that will use other transducers, like &lt;code&gt;mapping&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; compose(mapping(inc),filtering(is_even))(pairs)({0,1,2,3,4}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print (v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But wait, what&amp;rsquo;s the big idea?
Right now it looks much more complicated than just writing &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;, which is like half the amount of code, even without packing &lt;code&gt;end&lt;/code&gt; on the same line, and &lt;code&gt;is_even&lt;/code&gt; and &lt;code&gt;inc&lt;/code&gt; don&amp;rsquo;t have to deal with keys:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map&lt;/span&gt;(f, tbl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(tbl) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res[k]=f(v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter&lt;/span&gt;(pred, tbl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(tbl) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; pred(v) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            res[k] = v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt; (x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x+1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_even&lt;/span&gt; (x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x%2==0 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs(map(inc, filter(is_even, {0,1,2,3,4}))) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But there&amp;rsquo;s a big difference with this approach.
First, this code isn&amp;rsquo;t as general, as both &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; don&amp;rsquo;t know how to iterate things other than tables.
They also hard-code &lt;code&gt;pairs&lt;/code&gt; as part of their process, so we will always iterate through all keys no matter what our goal is.
Finally, this style produces intermediate tables on each step: first, &lt;code&gt;filter&lt;/code&gt; produces a table with even numbers, then &lt;code&gt;map&lt;/code&gt; consumes this table and produces an entirely new table with altered values.
Which wastes memory depending on the overall size of the data and gives GC extra work.&lt;/p&gt;
&lt;p&gt;Transducers fix all these issues - both &lt;code&gt;mapping&lt;/code&gt; and &lt;code&gt;filtering&lt;/code&gt; are abstracted from how we do the iteration itself.
And instead of producing intermediate tables, everything is done on a per-element level.
Here&amp;rsquo;s how we can visualize:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt; (k,x) print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;inc &amp;#34;&lt;/span&gt;..x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; k,x+1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is_even&lt;/span&gt; (_,x) print(x..&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; even?&amp;#34;&lt;/span&gt;, x%2==0) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; x%2==0 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; compose(mapping(inc),filtering(is_even))(pairs)({0,1,2,3,4}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 0 even?  true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- inc      0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- result   1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1 even?  false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2 even?  true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- inc      2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- result   3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3 even?  false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 4 even?  true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- inc      4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- result   5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, if the &lt;code&gt;x&lt;/code&gt; is even, we pass it to &lt;code&gt;inc&lt;/code&gt;, otherwise, we get another one and check it.
The &lt;a href=&#34;http://fasihkhatib.com/2018/01/06/transducers/&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Transducers&amp;rdquo; article by Fasih Khatib&lt;/a&gt; has a nice visualization for this process:&lt;/p&gt;
&lt;blockquote&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-26-iterator-based-transducers-in-lua/chain.gif&#34;
         alt=&#34;Figure 1: Chaining&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Chaining&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-26-iterator-based-transducers-in-lua/transduce.gif&#34;
         alt=&#34;Figure 2: Transducing&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Transducing&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;/blockquote&gt;
&lt;p&gt;Except, in our case, some values are simply dropped during the filtering step.
In order to understand how this works, let&amp;rsquo;s look closer at &lt;code&gt;f1&lt;/code&gt; from &lt;code&gt;filtering&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; f1 = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (recur, iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; f(...) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; recur(iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;As I mentioned, &lt;code&gt;step&lt;/code&gt; passes itself to &lt;code&gt;f1&lt;/code&gt;, along with the &lt;code&gt;iterable&lt;/code&gt;, and values from &lt;code&gt;next1&lt;/code&gt;.
This function mostly ignores the first two arguments and mainly works with &lt;code&gt;...&lt;/code&gt;.
But if &lt;code&gt;f&lt;/code&gt; returned &lt;code&gt;false&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;, we need to somehow continue the iteration until &lt;code&gt;f&lt;/code&gt; returns a truthful value, or until the &lt;code&gt;iterable&lt;/code&gt; is exhausted.
To achieve that, we recursively call back the &lt;code&gt;step&lt;/code&gt; function, called &lt;code&gt;recur&lt;/code&gt; here, and it produces a new value and calls &lt;code&gt;f1&lt;/code&gt; again.
Since both are tail calls, everything is optimized into a loop.&lt;/p&gt;
&lt;p&gt;I can prove that by creating an iterator that never exhausts, and wrapping it with &lt;code&gt;filtering&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ones&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; () &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 1,1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; filtering(is_even)(ones)() &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- even? 1 false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- even? 1 false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will never finish, but also won&amp;rsquo;t consume stack or memory.
&lt;code&gt;ones&lt;/code&gt; simply returns &lt;code&gt;1,1&lt;/code&gt; every time it is invoked, but &lt;code&gt;filtering&lt;/code&gt; looks for even values, so we&amp;rsquo;ll never reach the body of the loop.
And that&amp;rsquo;s another benefit of transducers - same as iterators, transducers remain lazy, and can work on infinite sets of data.&lt;/p&gt;
&lt;p&gt;Finally, let&amp;rsquo;s write a stateful transducer, such as &lt;code&gt;taking&lt;/code&gt;.
It&amp;rsquo;s going to terminate the iteration earlier, after &lt;code&gt;n&lt;/code&gt; elements were read:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;taking&lt;/span&gt;(n)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; count = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; count &amp;lt; n &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            count = count + 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;, ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may seem easy - all we do is that instead of accepting a filtering function, we accept a number, and check against it.
Otherwise, it&amp;rsquo;s exactly the same principle as &lt;code&gt;filtering&lt;/code&gt;, but we don&amp;rsquo;t need the recursion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; taking(4)(pairs)({a=1,b=2,c=3}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; print(k,v) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- all values are printed as the table has &amp;lt; 4 keys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- b 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; taking(4)(pairs)({1,2,3,4,5,6,7}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; print(v) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- only first 4 values are printed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, in the following example, we create a transducer that should take at most four elements from a collection:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;four_pairs = taking(4)(pairs)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What will be printed if we use it here?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; four_pairs({a=1,b=2,c=3}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; print(k,v) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; four_pairs({1,2,3,4,5,6,7}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; print(v) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;details&gt;
&lt;summary&gt;Results&lt;/summary&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- for k,v in four_pairs({a=1,b=2,c=3}) do print(k,v) end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- b 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- for _,v in four_pairs({1,2,3,4,5,6,7}) do print(v) end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;p&gt;People who are familiar with Rich Hickey&amp;rsquo;s talk &lt;a href=&#34;https://youtu.be/4KqUvG8HPYo?t=843&#34; target=&#34;_blank&#34;&gt;Inside Transducers&lt;/a&gt;, already know what&amp;rsquo;s the issue here, and why the result is different from the ones where we created transducers in each &lt;code&gt;for&lt;/code&gt; loop.
All stateful transducers must create their state anew every time they&amp;rsquo;re finalized.
In our case, the finalization happens when we&amp;rsquo;re passing a collection to the resulting iterator.
So in order to fix this we need to move where we&amp;rsquo;re initializing the &lt;code&gt;count&lt;/code&gt; variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- orig taking
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++ fixd taking
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -1,9 +1,9 @@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; function taking(n)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-    local count = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     return function (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         return function (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             return (function (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+                    local count = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     return function (iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         return (function (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 if nil ~= ... and count &amp;lt; n then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     count = count + 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It should be done as late as possible, right before we&amp;rsquo;re returning our &lt;code&gt;next&lt;/code&gt; function.
And because this iterator is stateful, we can&amp;rsquo;t share the &lt;code&gt;next&lt;/code&gt; function it returns with others, unlike the one we get from &lt;code&gt;pairs&lt;/code&gt;.
Now it will work as we&amp;rsquo;d expect:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;four_pairs = taking(4)(pairs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; four_pairs({a=1,b=2,c=3}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; print(k,v) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- b 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; four_pairs({1,2,3,4,5,6,7}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt; print(v) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As our final step in our descendant to functional madness, let&amp;rsquo;s write a &lt;code&gt;paritioning&lt;/code&gt; transducer, that will group individual elements into groups of &lt;code&gt;n&lt;/code&gt; elements.
It&amp;rsquo;s important to look at it, as it has a problem we haven&amp;rsquo;t encountered yet.
Also, remember when I said to you that the &lt;code&gt;step&lt;/code&gt; function must be a named one?
Well, I lied:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partitioning&lt;/span&gt; (n)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; count, arr = 0, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (i) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; i(i) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (x) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; i(i)(x) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (step)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (recur, iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; n == count &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; arr1 = arr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        arr1.n = count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        arr, count = {(...)}, 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; arr1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        count = count + 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        arr[count] = ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; recur(iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; count ~= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    arr.n,count = count,0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; arr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(step, iterable, next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;), ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a lot to take in.
First of all, there&amp;rsquo;s no real reason to make this as complicated as it is besides proving the point that I&amp;rsquo;m proficient with functions returning functions.
That thing in line 7 is a &lt;a href=&#34;https://en.wikipedia.org/wiki/Fixed-point_combinator#Fixed-point_combinators_in_lambda_calculus&#34; target=&#34;_blank&#34;&gt;Y combinator&lt;/a&gt; - I used it here to move the explicit creation of the named &lt;code&gt;step&lt;/code&gt; function into its argument and hence made it recursive without really defining it as a named function.
So, you can do that in Lua, but it&amp;rsquo;s here only for fun.
We can see that it works by writing another transducer that will use &lt;code&gt;table.concat&lt;/code&gt; to pretty-print the tables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table_formatter&lt;/span&gt; (t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt;..table.concat(t, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)..&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; s &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; compose(mapping(table_formatter),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 partitioning(3))(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (s) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; s:gmatch(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {f, o, o}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {b, a, r}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, as I mentioned, this transducer has a problem that no other transducers had up to this point.
Let&amp;rsquo;s try using it with ordinary &lt;code&gt;pairs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; partitioning(3)(pairs)({&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(k,table.concat(v, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- table: 0x555ff86717a0        nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- invalid key to &amp;#39;next&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- stack traceback:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;--      [C]: in function &amp;#39;next&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After we get the first partition, we immediately get an error.
This happens because &lt;code&gt;next&lt;/code&gt;, the function we internally use to get the next item from the &lt;code&gt;iterable&lt;/code&gt; object has kind of a feedback loop.
It uses the result of its last call to continue iteration.
Observe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;next({&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1, &amp;#34;a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;next({&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;}, 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2, &amp;#34;b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;next({&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;}, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- invalid key to &amp;#39;next&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- stack traceback:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;--         [C]: in function &amp;#39;next&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, when our iterator returns the table, it is passed to &lt;code&gt;next&lt;/code&gt; as the key, and because &lt;code&gt;next&lt;/code&gt; can&amp;rsquo;t find this key in the table, it throws an error.
This is also the reason, why we have to return keys unaltered from any function we pass to &lt;code&gt;mapping&lt;/code&gt;.
This is one major difference from Clojure because there we&amp;rsquo;re saying how to deal with that by finalizing the transducer with the reducing function.
But here we don&amp;rsquo;t have any reducing function.&lt;/p&gt;
&lt;p&gt;We could try to work around this, but there&amp;rsquo;s another glaring issue here.
Look at how we&amp;rsquo;re adding values to the partition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              count = count + 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              arr[count] = ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; recur(iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Even if we were to somehow store the last key, and pass it to the &lt;code&gt;next&lt;/code&gt; call we still store values in the array in a completely wrong way.
This is where Lua&amp;rsquo;s open iterator interface falls short.
Because there&amp;rsquo;s no guarantee that the first argument is a key and not actual da4a, we can&amp;rsquo;t just return the first argument, and put everything else into the array.
Moreover, if the iterator returns not a key-value pair, but more values, we don&amp;rsquo;t know how to put these either.&lt;/p&gt;
&lt;p&gt;The solution?&lt;/p&gt;
&lt;p&gt;Is of course more functions!
We&amp;rsquo;re going to tell &lt;code&gt;partitioning&lt;/code&gt; transducer upfront how it should handle the results.
This, of course, limits the generality of our system, but I think this is a testament to how well Clojure is designed.
Transducers were added to it basically without any internal change.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;em&gt;fixed&lt;/em&gt; version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;39
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partitioning&lt;/span&gt; (n, collect)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (iterator)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (next1, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; count, arr, last = 0, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (f, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (i, ...) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; i(i, ...) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (i, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; f(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (x, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; i(i, ...)(x, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                         &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (step)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (recur, iterable, ...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;nil&lt;/span&gt; ~= ... &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; n-1 == count &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; arr1, count1 = arr, count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        arr, count = {}, 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                   last = ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                   &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(collect(arr1, count1+1, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        count = count + 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; recur(iterable,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                     (&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                          last = ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                          &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                     &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(collect(arr, count, ...)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                &lt;span style=&#34;font-weight:bold&#34;&gt;elseif&lt;/span&gt; count ~= 0 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    count = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; last, arr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(step, iterable, next1(iterable, ...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;), ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)(iterator(...))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve &lt;em&gt;&amp;ldquo;fixed&amp;rdquo;&lt;/em&gt; the Y combinator to propagate all of its arguments into all of its functions, instead of just one, and added the &lt;code&gt;last&lt;/code&gt; key storage, so we could properly terminate the iteration, and return the array.
If you count just the keyword &lt;code&gt;function&lt;/code&gt; in this piece of code, it appears a whopping 13 times!
It&amp;rsquo;s crazy, yes even by my standards, I would never give such code a pass, but it&amp;rsquo;s nice to fool around and see how far can we push function manipulation style.
Can I remove the storage, and put it into the function&amp;rsquo;s arguments during anonymous recursion done with the Y combinator?
Eh, probably.
Will I do it?
Nah.&lt;/p&gt;
&lt;p&gt;What matters is that this code now works with &lt;code&gt;pairs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collector&lt;/span&gt;(arr, n, k, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arr[n]=v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; k, arr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;partition_three_pairs=partitioning(3,collector)(pairs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; partition_three_pairs({&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(table_formatter(v))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {a, b, c}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {d, e}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; _,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; partition_three_pairs({a=1,b=2,c=3,d=4,e=5}) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(table_formatter(v))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {1, 2, 5}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {3, 4}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It also correctly preserves the state, preventing it from leaking when we save the transducer finalizing it with &lt;code&gt;paris&lt;/code&gt;.
The same transducer works with the single-argument stateful iterator, provided a different &lt;code&gt;collector&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string_collector&lt;/span&gt; (arr, n, s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arr[n]=s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; arr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chars&lt;/span&gt; (s) &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; s:gmatch(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; t &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; partitioning(4,string_collector)(chars)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(table_formatter(t))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {f, o, o, b}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- {a, r}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this, I feel that my functional desires are fulfilled.
For now, at least.&lt;/p&gt;
&lt;p&gt;I know, this article was a wall of text and code, but it is mostly because I was really passionate about the topic, and wanted to get it out of my system, so I could continue working on the game3.
If you&amp;rsquo;ve made it til here, and you have questions about the code, either because my explanations were unclear, or simply because there&amp;rsquo;s not enough of them, feel free to contact me, and I will try to answer, and update the post.&lt;/p&gt;
&lt;p&gt;If instead you looked at the code and thought something like &amp;ldquo;well that escalated quickly&amp;rdquo;, or that I&amp;rsquo;m just a crazy person, doing over-complicated things - well that&amp;rsquo;s a valid point of view as well!
I wouldn&amp;rsquo;t say that these transducers are practical, and their runtime characteristics and impact on the Lua runtime performance is unclear to me.
I mean, when I talked about how &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; produce intermediate collections that are thrown away once we&amp;rsquo;re done, and how it is bad, having a function wrapping another 12 nested function wrappers with a Y combinator in the middle isn&amp;rsquo;t much better.
But still, I feel great just because I managed to make it work, and it isn&amp;rsquo;t completely insane, as all of the principles are pretty simple.
Functional decorators existed for a long time, and these transducers are basically it.&lt;/p&gt;
&lt;p&gt;Anyhow, I hope you&amp;rsquo;ve found this interesting.
Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Iterator-based transducers in Lua&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 26 Sep 2023 23:54:00 +0300</pubDate>
    </item><item>
      <title>Game3 w2/3</title>
      <link>https://andreyor.st/posts/2023-09-24-game3-w23/</link>
      <guid>https://andreyor.st/posts/2023-09-24-game3-w23/</guid>
      <description>&lt;p&gt;Another week passed, but I didn&amp;rsquo;t manage to squeeze out much spare time to make any significant progress with the game.
Not like I didn&amp;rsquo;t do anything, but the game is far from being playable.
This week I, unfortunately, could spend only a single day working on a game, because every day after work I had some personal stuff to take care of, which took all of my after-work hours.
But it doesn&amp;rsquo;t matter, the challenge is a challenge!
Hopefully, the next week will be a bit less busy.
Although the stuff happening right now is very exciting and very important, so if the next week is busy again - so be it.&lt;/p&gt;
&lt;p&gt;Anyway, here&amp;rsquo;s the progress so far:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-09-24-game3-w23/game.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a prototype.
I&amp;rsquo;m experimenting with enemy patterns, like a simple sine wave, or tracking enemies.
No collision has been implemented yet.
This is my plan for the next and final week.
As well as doing more animation, as the ship is just a cardboard right now, making weapons work, and not just fly with you, and implementing a scoring system.
Probably that&amp;rsquo;s the most I&amp;rsquo;ll be able to do.&lt;/p&gt;
&lt;p&gt;Another thing I want to look into is rotating sprites, as I want to spawn meteorites semi-randomly after some time passes in the game, so the game becomes harder.
These meteorites will shatter, and smaller parts will also damage the player, making it harder to maneuver.
But that&amp;rsquo;s probably the least prioritized thing as of this moment.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game3 w2/3&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 24 Sep 2023 20:55:00 +0300</pubDate>
    </item><item>
      <title>Why Kakoune</title>
      <link>https://andreyor.st/posts/2023-09-20-why-kakoune/</link>
      <guid>https://andreyor.st/posts/2023-09-20-why-kakoune/</guid>
      <description>&lt;p&gt;Recently I&amp;rsquo;ve stumbled upon a video about Kakoune, a code editor: &lt;a href=&#34;https://www.youtube.com/watch?v=5WLlLxU2EZE&#34; target=&#34;_blank&#34;&gt;Idiot user tries to use Kakoune (for notes? Also Helix?)&lt;/a&gt;.
Funnily enough, I was &lt;a href=&#34;https://www.youtube.com/watch?v=5WLlLxU2EZE&amp;amp;t=1004s&#34; target=&#34;_blank&#34;&gt;mentioned&lt;/a&gt; in this video, which was a surprise, and made me laugh for quite a while:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s go back to the official plugins page.
This guy has made a bunch of plugins.
&lt;strong&gt;Who is he?&lt;/strong&gt;
&lt;em&gt;How is he able to make such good use of Kakoune?&lt;/em&gt;
&lt;strong&gt;Oh, he&amp;rsquo;s an Emacs user!&lt;/strong&gt;
&lt;strong&gt;Of course!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, I am.&lt;/p&gt;
&lt;p&gt;Even though the video &lt;strong&gt;is&lt;/strong&gt; about Kakoune, the author&amp;rsquo;s main focus is note-taking and the oddities that come with this process when using a &lt;em&gt;code editor&lt;/em&gt; to edit &lt;em&gt;text&lt;/em&gt;.
Kakoune advertises itself as a code editor for the most part, and I have to agree.
As far as I know, Maxime Coste (&lt;a href=&#34;https://github.com/mawww&#34; target=&#34;_blank&#34;&gt;@mawww&lt;/a&gt;), the creator of Kakoune, made it because of the desire for a better programming experience.
As a result, a small and contained code editor was made.
And I can appreciate a desire of the system one can fully grasp and understand.&lt;/p&gt;
&lt;p&gt;Kakoune is relatively small, compared to Emacs and Vim that is.
It doesn&amp;rsquo;t feature a scripting language, instead relying on shelling out if you need any programmable features.
It&amp;rsquo;s a clever trick, and the editor exposes its internal state as a set of shell variables, so you still can do interactive things based on your workflow.
And I did a lot of this back in the day when I used Kakoune.&lt;/p&gt;
&lt;p&gt;I have mentioned Kakoune in this blog previously, but it was rather sparse.
The reason for that is stated in the video pretty accurately - I use Emacs and not Kakoune, so there&amp;rsquo;s little to no reason for me to write about it besides occasional praise or comparisons.
I mention it on my about page, and in various text-editor-related posts, but that&amp;rsquo;s it.
I don&amp;rsquo;t participate in the Kakoune community anymore, and no longer actively maintain my packages, as I no longer use Kakoune.&lt;/p&gt;
&lt;p&gt;But I still need to address &lt;a href=&#34;https://youtu.be/5WLlLxU2EZE?t=1017&#34; target=&#34;_blank&#34;&gt;this&lt;/a&gt; point of the video - I wasn&amp;rsquo;t an Emacs user when I started with Kakoune.
Before Kakoune I was a Vim user!
And transition from Vim to Kakoune was caused by several factors, one of which is again stated in the video:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;hellip;and people have written so many damn Vim plugins over the years that if you have a need it&amp;rsquo;s already been addressed like three or four different ways.
So with Vim you could just piece together your ideal text editor like LEGO bricks&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&amp;rsquo;s exactly my problem with Vim - too many ways to do the same thing.
At the time, I was working with SoC in C and started using the &lt;a href=&#34;https://github.com/dense-analysis/ale&#34; target=&#34;_blank&#34;&gt;Ale&lt;/a&gt; plugin for asynchronous linting of the project, as the synchronous linting was quite slow.
This was before LSP inception - just look at &lt;a href=&#34;https://github.com/dense-analysis/ale/blob/master/supported-tools.md&#34; target=&#34;_blank&#34;&gt;how many tools Ale supports&lt;/a&gt;.
As far as I remember LSP was added to Ale much later, when competing plugins showed up.&lt;/p&gt;
&lt;p&gt;Competing plugins.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s nothing bad with competition on its own, and in Emacs, this is also present, with many plugins, but in Vim&amp;rsquo;s case, I feel that people created most of the plugins purely because of the NIH&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; syndrome.
I lost count of how many plugins provided autocomplete interfaces, there were tons of list-narrowing frameworks, plugin managers, and snippet managers, and everything was poorly integrated with each other.
I remember that some autocomplete plugins did not integrate well or at all with snippets, some synchronous completion providers were not supported by asynchronous completion frameworks, and so on.
Again, this was before LSP came to the scene and basically became a standard for these features.
So perhaps the situation is a bit better today, but I still have doubts.
NeoVim people are going crazy over Lua API, writing their configs in Fennel, and making new Lua-based plugins that may or may not be compatible with the rest of the ecosystem.&lt;/p&gt;
&lt;p&gt;Fact is, you &lt;em&gt;can&lt;/em&gt; piece your dream text editor like &lt;em&gt;LEGO&lt;/em&gt; bricks, just beware that some of these bricks are actually &lt;a href=&#34;https://en.wikipedia.org/wiki/Lego_Duplo&#34; target=&#34;_blank&#34;&gt;Duplo&lt;/a&gt; blocks, some are &lt;a href=&#34;https://en.wikipedia.org/wiki/Cobi_%28building_blocks%29&#34; target=&#34;_blank&#34;&gt;COBI&lt;/a&gt; bricks, lots and lots are probably &lt;a href=&#34;https://brickscompare.com/brands/8-lele&#34; target=&#34;_blank&#34;&gt;LELE&lt;/a&gt;, and some are even freakin&amp;rsquo; &lt;em&gt;&lt;a href=&#34;https://andreyor.st/2023-09-20-why-kakoune/oleg.jpg&#34;&gt;OLEG&lt;/a&gt;&lt;/em&gt;.
Well, at least that was the situation when I used Vim, I gave up on updating my config around 2018 and made the switch to Kakoune.
By that time I already made three plugins for Vim because I was unsatisfied with existing ones, but they were crappy too.
Integrating these plugins into different other plugins was a huge pain.
So I &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/d91e8ca4ccb59c89c2043d5d2c4eb8af3fbe498d&#34; target=&#34;_blank&#34;&gt;made the switch&lt;/a&gt;.
You can trace the history from that point if you&amp;rsquo;re interested in my Kakoune journey (why would you be though).&lt;/p&gt;
&lt;p&gt;Obviously, I missed a lot of features from Vim, and Kakoune actually has an entry on their wiki on how to migrate from Vim.
Unfortunately, though, the suggestions were either too hardcore-minimalist or uncooperative.
For example, Vim&amp;rsquo;s &lt;code&gt;smarttab&lt;/code&gt; feature didn&amp;rsquo;t exist, and &lt;code&gt;expandtab&lt;/code&gt; was &lt;a href=&#34;https://github.com/mawww/kakoune/wiki/Indentation-and-Tabulation/e6756dc1a8af07add53145a9251eeb2ba0e0c5a5&#34; target=&#34;_blank&#34;&gt;suggested&lt;/a&gt; to be done via hooks.
Not that it was wrong, but it was suggested when people asked about a very specific feature of Vim, and these did not provide the same feature as in Vim.
So I started writing plugins.&lt;/p&gt;
&lt;p&gt;However, Kakoune didn&amp;rsquo;t have conventional plugins at all at that time.
Well, there was a section with plugins on the official page, but there was no real ecosystem.
There was nothing such as Vimplug if you will.&lt;/p&gt;
&lt;p&gt;Installing plugins meant you had to manually copy files around, or load them pathogen-style, but the process wasn&amp;rsquo;t convenient or easy to automate in my opinion.
Updating plugins installed in this way was problematic too.
This motivated me to make &lt;a href=&#34;https://github.com/andreyorst/plug.kak&#34; target=&#34;_blank&#34;&gt;plug.kak&lt;/a&gt;.
And then I started experimenting more and more with other interesting plugins.&lt;/p&gt;
&lt;p&gt;But, around the same time I switched to Kakoune, I briefly tried Emacs.
In reality, I tried Emacs like 4 times at that point, the earliest one dates back to around 2010.
All four times I did not succeed, but something gravitated me to it for some reason.
This last one actually was a reason why I made some plugins like &lt;a href=&#34;https://github.com/andreyorst/langmap.kak&#34; target=&#34;_blank&#34;&gt;langmap.kak&lt;/a&gt; or &lt;a href=&#34;https://github.com/andreyorst/kaktree&#34; target=&#34;_blank&#34;&gt;kaktree&lt;/a&gt;, which resemble what I saw in Emacs at that point.
Many plugins were inspired by Vim, like &lt;a href=&#34;https://github.com/andreyorst/smarttab.kak&#34; target=&#34;_blank&#34;&gt;smarttab.kak&lt;/a&gt;, &lt;a href=&#34;https://github.com/andreyorst/powerline.kak&#34; target=&#34;_blank&#34;&gt;powerline.kak&lt;/a&gt;, &lt;a href=&#34;https://github.com/andreyorst/fzf.kak&#34; target=&#34;_blank&#34;&gt;fzf.kak&lt;/a&gt;, &lt;a href=&#34;https://github.com/andreyorst/tagbar.kak&#34; target=&#34;_blank&#34;&gt;tagbar.kak&lt;/a&gt;, equivalents to which I daily used in Vim before.
And at that time, Kakoune really did everything I needed and was a very capable code editor.&lt;/p&gt;
&lt;p&gt;But I still wanted something more.
So why I made the switch to Emacs - but for a bit different reasons.&lt;/p&gt;
&lt;p&gt;First of all, I started enjoying writing more prose instead of just writing code.
And if you&amp;rsquo;ve watched the video I linked above, the author similarly wants a text editor, not a code editor.
There&amp;rsquo;s &lt;a href=&#34;https://www.youtube.com/watch?v=XRpHIa-2XCE&#34; target=&#34;_blank&#34;&gt;another video&lt;/a&gt; on their channel about note-taking, featuring a lot of programs made specifically for this task, and it features a text editor section at the end in which the author talks about Emacs and Vim, briefly touching Kakoune and Helix.
What they&amp;rsquo;re saying about Emacs is also very similar to what I&amp;rsquo;ve experienced, although I didn&amp;rsquo;t use an Emacs distribution, I started with vanilla&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Org Mode.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know how to explain this to a non-Emacs, non-Org person, but every time someone asks the &amp;ldquo;Why Emacs?&amp;rdquo; question, Org Mode is somewhere at the top of the answers.
And I never understood that, until I tried for myself.
And boy are they right.
But before I understood that, there was a &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/442941e8a230ccbb075a7bdfcf6075367c46cd73&#34; target=&#34;_blank&#34;&gt;long&lt;/a&gt; period of &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/9088b4fd041005c6143de8de012541f0bc6f913f&#34; target=&#34;_blank&#34;&gt;adoption&lt;/a&gt;.
I still used Kakoune, but more and more I was shifted towards Emacs - it slowly consumed me.&lt;/p&gt;
&lt;p&gt;A big part of that was that I started writing in Lisps.
Emacs is &lt;strong&gt;the king&lt;/strong&gt; when it comes to Lisp editing.
Plugins for various Schemes, that I used to do tasks from the SICP book were amazing, and Kakoune &lt;code&gt;:repl&lt;/code&gt; command paled in comparison.
Though I can&amp;rsquo;t blame anyone here - Emacs is a lisp machine on its own, it&amp;rsquo;s bound to have great lisp editing experience.&lt;/p&gt;
&lt;p&gt;Though lisp wasn&amp;rsquo;t my primary language back then, more like a novelty.
I used Rust and considered switching jobs from a C engineer to a Rust back-end developer.
Rust seemed both a perspective and a &lt;em&gt;safe&lt;/em&gt; enough bet for the foreseeable future.
Who knew how the tables would turn?!&lt;/p&gt;
&lt;p&gt;Kakoune actually was great as a Rust IDE of sorts.
The &lt;a href=&#34;https://github.com/kak-lsp/kak-lsp&#34; target=&#34;_blank&#34;&gt;kak-lsp&lt;/a&gt; plugin was on it, written in Rust it supported Rust well.
And it helped me at work with C too.
That was 2019, the year I started using Emacs for real.&lt;/p&gt;
&lt;p&gt;That year, I made my first, kinda big post, in which I realized that I wanted to write more.
Ironically, it was a &lt;a href=&#34;https://discuss.kakoune.com/t/i-have-been-using-emacs-at-work-for-whole-week/&#34; target=&#34;_blank&#34;&gt;post about Emacs on the Kakoune forum&lt;/a&gt;.
It was even written partly in Emacs and partly in Kakoune - I was comparing editors at that time, much like the author of already mentioned videos.
But this day signified that I was ready to fully migrate to Emacs - my config was more or less ready for work at that point.
Emacs seemed better at writing, although I was missing cool Kakoune features, such as multiple selections, a lot.
I started writing this blog in 2020, and it was done in Emacs from the get-go.
Not so long after that, I moved to Emacs &lt;a href=&#34;https://github.com/andreyorst/dotfiles/commit/0e31f525b069f097a99cd1876a009f03cd26299c&#34; target=&#34;_blank&#34;&gt;completely&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I used Kakoune for 1.9835616438356165 years (first commit on Jul 24 2018, last commit on Jul 17 2020).&lt;/p&gt;
&lt;p&gt;But this post actually is called &amp;ldquo;Why Kakoune&amp;rdquo; and not &amp;ldquo;Why I switched to Emacs&amp;rdquo;, so let&amp;rsquo;s address that!&lt;/p&gt;
&lt;h2 id=&#34;why-kakoune&#34;&gt;Why Kakoune&lt;/h2&gt;
&lt;p&gt;What an awfully long preamble.
If you read that, you have my thanks.
If not - fair enough.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s kinda weird to read reasoning on why someone should use Kakoune from someone who&amp;rsquo;s not using Kakoune right now and hasn&amp;rsquo;t for another three years already.
But, as far as I can see, not much has changed in Kakoune since!
Which, actually, is great - I can actually just check out to a commit previous to the one I deleted my Kakoune config in the &lt;code&gt;dotfiles&lt;/code&gt; repository, and run it.
A fresh clone of Kakoune&amp;rsquo;s latest stable release builds in just two minutes on my machine, and loads my old configuration without too many errors:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-09-20-why-kakoune/kakoune.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;At this point of the post I wanted to write about stability, but as it seems, the situation isn&amp;rsquo;t that great.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some plugins simply no longer exist.&lt;/li&gt;
&lt;li&gt;Some defaults were changed in 2022, making keys behave differently (can be turned back via a remap)&lt;/li&gt;
&lt;li&gt;Some changes were made to how Kakscript is interpreted.&lt;/li&gt;
&lt;li&gt;Most of my plugins broke (but that&amp;rsquo;s on me).&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s possibly more, but I&amp;rsquo;m out of the loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What&amp;rsquo;s hasn&amp;rsquo;t changed is that &lt;a href=&#34;https://discuss.kakoune.com/t/ive-lost-my-syntax-highlighting/&#34; target=&#34;_blank&#34;&gt;people&lt;/a&gt; &lt;a href=&#34;https://discuss.kakoune.com/t/autoload-directory-disables-doc-command/1656&#34; target=&#34;_blank&#34;&gt;still&lt;/a&gt; &lt;a href=&#34;https://github.com/mawww/kakoune/issues/4301&#34; target=&#34;_blank&#34;&gt;stumble&lt;/a&gt; on the &lt;code&gt;autoload&lt;/code&gt; directory after all these &lt;a href=&#34;https://github.com/mawww/kakoune/issues/1&#34; target=&#34;_blank&#34;&gt;years&lt;/a&gt;.
Because there&amp;rsquo;s no plugin manager in Kakoune, it relies on storing scripts you want to load automatically during startup in the &lt;code&gt;~/.config/kak/autoload&lt;/code&gt; directory.
This, however, for some weird reason, disables loading a system-wide Kakoune &lt;code&gt;autoload&lt;/code&gt; directory, and Kakoune simply stops loading all of its inbuilt features that are shipped as &lt;code&gt;.kak&lt;/code&gt; files.
I also experienced this problem, and it was one of the main reasons for making &lt;code&gt;plug.kak&lt;/code&gt;.
So, if anything above seems too weird, perhaps Kakoune is not for you.&lt;/p&gt;
&lt;p&gt;But, given all that, Kakoune hasn&amp;rsquo;t changed that drastically over the three years I haven&amp;rsquo;t used it, and that&amp;rsquo;s a good thing.
Even now, I can still edit files in it pretty comfortably after my brain does the switch from Emacs keybindings to a modal model.
For the most part, that is, some habits are hard.&lt;/p&gt;
&lt;p&gt;But one thing, that I think can be a main reason why people should try Kakoune, in my opinion, is its POSIX integration.
Back in the day, I really liked this idea, can&amp;rsquo;t say so today&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, &lt;strong&gt;but&lt;/strong&gt;, it&amp;rsquo;s still a good reason why Kakoune is interesting.&lt;/p&gt;
&lt;p&gt;I mentioned that I made plugins for Kakoune, and because of that I now know POSIX sh pretty well.
Not that I need this knowledge that often, but when I do, I&amp;rsquo;m glad Kakoune taught me well.
The same goes for other POSIX tools - Kakoune basically forces you to learn your shell stuff, because there&amp;rsquo;s no other way to be productive in Kakoune.
Everything is done via shelling out to use some tool like &lt;code&gt;fmt&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;And when shell tools are not enough you can always call different programming languages from the shell.
For example, some of my plugins are written in Perl of all languages.
And while I can&amp;rsquo;t say that I&amp;rsquo;m proud of that, or that I know Perl that well, I can still say that Kakoune &lt;a href=&#34;https://github.com/andreyorst/langmap.kak/blob/fe72a9980988c97ec901df1c36129b6959468b08/perl/langmap.pl&#34; target=&#34;_blank&#34;&gt;made&lt;/a&gt; me &lt;a href=&#34;https://github.com/andreyorst/langmap.kak/blob/fe72a9980988c97ec901df1c36129b6959468b08/perl/display_layout.pl&#34; target=&#34;_blank&#34;&gt;learn&lt;/a&gt; &lt;a href=&#34;https://github.com/andreyorst/kaktree/blob/acd47e0c8549afe1634a79a5bbd6d883daa8ba0a/perl/kaktree.pl&#34; target=&#34;_blank&#34;&gt;Perl&lt;/a&gt;, well, to some degree.
Also, &lt;a href=&#34;https://github.com/andreyorst/dotfiles/blob/187ebb84f9542b76a4f3c3e08f9533cd8187faa1/.config/kak/commands.kak#L151-L192&#34; target=&#34;_blank&#34;&gt;Awk&lt;/a&gt;.
And I still occasionally use both when I need to send a code snippet to my colleague so that they can send me some filtered logs instead of full logs.
Because that&amp;rsquo;s what these tools excel at, and learning how to use them from within an editor really makes it apparent how they can be useful.
So Kakoune really helps you learn your standard tools, and some extra things too.&lt;/p&gt;
&lt;p&gt;Another thing I think can be said is that Kakoune really makes you learn and understand regular expressions.
When I started using Kakoune, I once told my friend that I started using an editor that is built around using regular expressions for text manipulation.
They were quite skeptical, because I didn&amp;rsquo;t know regular expressions back then, and they had some experience and said that it&amp;rsquo;s a terrible idea to use them at all.
But turns out, that regular expressions are actually easy to learn, and Kakoune really helps with that, because you&amp;rsquo;re constantly creating multiple selections, selections in selections, and filtering selections - all done with regexes.
So, if you think that regexes are hard and you&amp;rsquo;ll never learn them (and you&amp;rsquo;re a Vim user by chance), give Kakoune a try.&lt;/p&gt;
&lt;p&gt;And finally, Kakoune is just fun!
Especially if you&amp;rsquo;re a seasoned Vim user, the inverted paradigm of object-verb really messes with your brain.
I think Kakoune features a really unique editing model, where it doesn&amp;rsquo;t need any separate mode for selecting text - all motions do it automatically.
When I started, I adjusted to the object verb paradigm pretty quickly, it&amp;rsquo;s very natural to how things are done - in real life, we usually don&amp;rsquo;t think upfront what we want to clean and then how many of &lt;em&gt;what was that&lt;/em&gt;, ah yeah the shelves.
We think that these shelves are dusty and we need to clean them.
I should probably do it right now.&lt;/p&gt;
&lt;p&gt;Anyway, a TL;DR for this could as well have been:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kakoune gives you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Small and understandable core.&lt;/li&gt;
&lt;li&gt;Proficiency with POSIX tools,
&lt;ul&gt;
&lt;li&gt;and maybe even some programming languages other than &lt;code&gt;sh&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Structural regular expressions as a central way of text manipulation.
&lt;ul&gt;
&lt;li&gt;With multiple selections created via regular expressions, acting upon regular expressions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fresh take on the modal editing paradigm.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, yeah, Kakoune definitively deserves your attention, if you&amp;rsquo;re into experiments with your workflow.
I, certainly, am.
At least, I was, now I do everything from Emacs.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Not Invented Here.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Though, I tried Spacemacs for a very brief period, mostly to see what&amp;rsquo;s there, and what can I have in Emacs.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Emacs, after some time, makes it obvious that you don&amp;rsquo;t need shells for most of the tasks, if not for all.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Why Kakoune&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 20 Sep 2023 22:59:00 +0300</pubDate>
    </item><item>
      <title>Game3 W?/4</title>
      <link>https://andreyor.st/posts/2023-09-16-game3-w4/</link>
      <guid>https://andreyor.st/posts/2023-09-16-game3-w4/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m working on the next game, although I gave myself an extended period of rest.
After failing to complete the last one I needed to distract myself a bit from this activity, so I worked a bit on Fennel stuff, played some games, and I think I&amp;rsquo;m back in business by now.
I have an interesting thing going on with my productivity - it comes in waves.
What I mean is that I can go onto programming frenzy for several months, and then once I feel burned out, I can just play games for another full month straight.
Though I get tired of games too, and if by that time I feel that I&amp;rsquo;m not ready for programming yet, I can read some technical books, or even just some manga if I still feel too tired to be productive.&lt;/p&gt;
&lt;p&gt;So this five month marathon is a bit hard for me, as I basically have to give up on long periods of rest, and juggle my free time to actually have some time to work on these projects.
While these games are nothing special, I feel like I&amp;rsquo;m still learning new stuff, and thus this is beneficial for me still.
Though, at some I actually thought of dropping the whole idea, and starting a more complex project that I was thinking about for a lot of time already.
But I decided to leave it for the next year, as I still need a lot to learn.
But, back on the topic.&lt;/p&gt;
&lt;p&gt;This post actually marks the end of only the second week of the current game.
How come, you might ask?
To put it simply, I miscalculated a bit, and in reality I had another week on the previous game by the time I dropped it.
So, technically, I could probably finish that game, but the burnout got me, so that&amp;rsquo;s that.&lt;/p&gt;
&lt;p&gt;As for this game, I have a little to show.
As it is a side-scrolling shooter, I designed a basic ship with some shooting modules, and some powerup icons.
I considered to not making any graphics for this one, and doing everything with just primitives, like triangles, circles and so on, but after trying to draw a ship like this I dropped the idea and returned to Pixel Studio.
Here are the results so far:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/sprites.png&#34; width=&#34;100%&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The ship turned out to be a bit too big, but I decided that I can make a game with larger assets for a change.
So the enemy also uses 4 sprites, instead of just one, as in my previous games.&lt;/p&gt;
&lt;p&gt;And here are the enemies animated:&lt;/p&gt;
&lt;div class=&#34;grid-gallery&#34;&gt;
  &lt;div class=&#34;grid-gallery-row&#34; style=&#34;display: flex&#34;&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/roaming.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/roaming-2.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;figcaption&gt;
  &lt;p&gt;Movement animations&lt;/p&gt;
&lt;/figcaption&gt;
&lt;div class=&#34;grid-gallery-row&#34; style=&#34;display: flex&#34;&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/exploding.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-09-16-game3-w4/explosion-2.gif&#34; width=&#34;40%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;figcaption&gt;
  &lt;p&gt;Explosion animations&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/div&gt;
&lt;p&gt;Obviously, I need to add more enemy variety, with different patterns, but designing enemies is hard.
BTW, if you&amp;rsquo;re curious how I draw things on the phone, here&amp;rsquo;s a time-lapse:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop&gt;&lt;source src=&#34;https://andreyor.st/2023-09-16-game3-w4/timelapse.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Though, I usually don&amp;rsquo;t do it in the landscape mode, portrait mode works better for me, especially with a stylus.
This process was recorded in landscape just for viewing convenience.&lt;/p&gt;
&lt;p&gt;On the technical side of things, I already implemented a basic movement with linear interpolation for the flying modules, and implemented some enemy patterns, but there&amp;rsquo;s no actual interactions yet.
I&amp;rsquo;m kinda torn on the idea of including &lt;code&gt;bump.lua&lt;/code&gt; again, as I feel like that this game can be done without any collision library.
At the same time, having a collision library may make things much simpler, so I&amp;rsquo;m still thinking how to approach this game.&lt;/p&gt;
&lt;p&gt;For the &lt;em&gt;record&lt;/em&gt;, I basically dropped the idea of making &lt;em&gt;any&lt;/em&gt; kind of music for these games because I just can&amp;rsquo;t get myself to work on it.
I do plan to take some courses on music composition for future projects, though.
Sound effects are challenging enough already by themselves.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for this week!
Hopefully, I&amp;rsquo;ll manage to finish the game this time, though I already lost one week.
Let&amp;rsquo;s say, this is week 1/3 instead of 2/4 shall we?
Feels less demotivating this way.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game3 W?/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 16 Sep 2023 01:59:00 +0300</pubDate>
    </item><item>
      <title>Migrating from LSP-Mode to Eglot</title>
      <link>https://andreyor.st/posts/2023-09-09-migrating-from-lsp-mode-to-eglot/</link>
      <guid>https://andreyor.st/posts/2023-09-09-migrating-from-lsp-mode-to-eglot/</guid>
      <description>&lt;p&gt;Recently, I decided to try the now inbuilt LSP client called &lt;a href=&#34;https://github.com/joaotavora/eglot&#34; target=&#34;_blank&#34;&gt;Eglot&lt;/a&gt;.
I&amp;rsquo;ve been using the &lt;a href=&#34;https://github.com/emacs-lsp/lsp-mode&#34; target=&#34;_blank&#34;&gt;lsp-mode&lt;/a&gt; package for some years and while I don&amp;rsquo;t have any problems with it, I decided to try the in-house solution.
Though, I already tried Eglot in the past, and it didn&amp;rsquo;t work for me, due to some complications with the language I&amp;rsquo;ve tried to use it with.
At the time it didn&amp;rsquo;t support Clojure, and while adding it wasn&amp;rsquo;t hard, some features did not work.
Which wasn&amp;rsquo;t the case with &lt;code&gt;lsp-mode&lt;/code&gt;, thus I used it instead.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;ll outline some problems I encountered, which are mostly Clojure-related.
At this point, I can&amp;rsquo;t say if I will actually move to Eglot, but I plan to use it for some time to see if I miss any features from &lt;code&gt;lsp-mode&lt;/code&gt;.
Until then, it will stay in my private configuration.&lt;/p&gt;
&lt;h2 id=&#34;configuration-and-installation&#34;&gt;Configuration and installation&lt;/h2&gt;
&lt;p&gt;I often see claims that &lt;code&gt;lsp-mode&lt;/code&gt; packs too many features.
While true, they&amp;rsquo;re all mostly optional and individually configurable.
Over the years, I&amp;rsquo;ve configured &lt;code&gt;lsp-mode&lt;/code&gt; in a fairly minimal way.
You see, with Clojure, and other lisps for that matter, language servers are somewhat inferior, because there&amp;rsquo;s a much more accurate way to obtain information about the code.
I, of course, talk about the REPL.
Being a dynamic environment, we can ask it about its state, known functions, macros, available modules, etc.
Of course, it depends on the implementation of the REPL, and not all are created equally, but the one I&amp;rsquo;m using (&lt;a href=&#34;https://nrepl.org/nrepl/index.html&#34; target=&#34;_blank&#34;&gt;nREPL&lt;/a&gt;) is quite capable.
Language server has to do all of that statically, using their own parsers, tracking of variables, modules, and so on.&lt;/p&gt;
&lt;p&gt;Because of that, I don&amp;rsquo;t really use most of the language server&amp;rsquo;s features - only linting, and occasionally go to definition.
If it wasn&amp;rsquo;t for one specific feature missing from &lt;a href=&#34;https://github.com/clojure-emacs/cider&#34; target=&#34;_blank&#34;&gt;CIDER&lt;/a&gt;, I wouldn&amp;rsquo;t use language server at all, I think.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my &lt;code&gt;lsp-mode&lt;/code&gt; configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-diagnostics-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-mode-maybe&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-mode-maybe&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-mode&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-keymap-prefix&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;C-c l&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-diagnostics-provider&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:flymake&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-provider&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:none&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-session-file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.lsp-session&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-emacs-directory&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-log-io&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-keep-workspace-alive&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-idle-delay&lt;/span&gt; 0.5)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-xref&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-auto-configure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-eldoc-enable-hover&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-dap-auto-configure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-file-watchers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-folding&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-imenu&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-indentation&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-links&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-on-type-formatting&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-suggest-server-download&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-symbol-highlighting&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-text-document-color&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; completion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-enable-additional-text-edit&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-enable-snippet&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-show-kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; headerline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-headerline-breadcrumb-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-headerline-breadcrumb-enable-diagnostics&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-headerline-breadcrumb-enable-symbol-numbers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-headerline-breadcrumb-icons-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; modeline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-modeline-code-actions-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-modeline-diagnostics-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-modeline-workspace-status-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-signature-doc-lines&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; lens&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-lens-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; semantic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-semantic-tokens-enable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-use-plists&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s quite big, actually.
Most of it, however, is disabling features I don&amp;rsquo;t need.
But it&amp;rsquo;s not all of it, here&amp;rsquo;s the rest:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-clojure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:demand&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-toggle-lsp-completion-maybe&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-toggle-lsp-completion-maybe&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-completion-mode&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-mode&lt;/span&gt;) -1 1))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-clojure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:no-require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurec-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurescript-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have a separate configuration section for &lt;code&gt;lsp-clojure&lt;/code&gt;, which is a submodule in the &lt;code&gt;lsp-mode&lt;/code&gt; package.
It&amp;rsquo;s separated into two blocks, so I can load one eagerly, and some other settings lazily without using explicit &lt;code&gt;eval-after-load&lt;/code&gt; in &lt;code&gt;use-package&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-java&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:demand&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;openjdk-11-path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;openjdk-11-path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-java-java-path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;openjdk-11-path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-java&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:no-require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;java-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same thing for &lt;code&gt;lsp-java&lt;/code&gt; which, however, is an external package.
And a similar thing for Scala language server, called Metals:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-metals&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-metals-server-args&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-J-Dmetals.allow-multiline-string-formatting=off&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scala-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But that&amp;rsquo;s not all, I also tweak the &lt;code&gt;lsp-treemacs&lt;/code&gt; package, which I don&amp;rsquo;t really use, but if it occasionally pops up I&amp;rsquo;d like to see it in a less noisy way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-treemacs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:defer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lsp-treemacs-theme&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Iconless&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Few things to note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I know about the &lt;code&gt;lsp-auto-configure&lt;/code&gt; custom, and set it to &lt;code&gt;nil&lt;/code&gt;.
My problem with such customs is that it&amp;rsquo;s not always means that it&amp;rsquo;s properly used in the codebase.
Some features may not look at it when the &lt;code&gt;lsp-mode&lt;/code&gt; is initialized, and I don&amp;rsquo;t want to study the codebase to see if it is used or not, so I just prefer more explicit configuration.
Yet, I don&amp;rsquo;t want to update the list of options all the time, so that&amp;rsquo;s why I set it to &lt;code&gt;nil&lt;/code&gt;, so the newly added options are disabled automatically, if they&amp;rsquo;re properly implemented, that is.
If not, they&amp;rsquo;ll pop in and I&amp;rsquo;ll notice them.&lt;/li&gt;
&lt;li&gt;I set &lt;code&gt;lsp-completion-enable&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; but I don&amp;rsquo;t want it to be enabled when I use CIDER, because the run-time completions give me better results.
So I disable &lt;code&gt;lsp-completion-mode&lt;/code&gt; in a CIDER-specific hook.
I also re-enable it, once I quit CIDER session for the current buffer.&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t need most of the features, even for non-REPL languages, such as Java or Scala.
Mainly because I don&amp;rsquo;t write code in these languages and mostly only read them, so I really only need the navigation part of LSP.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So my personal use-cases for LSP are a bit specific.
I actually prefer my editor to have less smart features, so for example my auto-complete isn&amp;rsquo;t auto at all, I manually trigger it only when I need it.
Thus, I don&amp;rsquo;t have that many language servers configured, as the things I occasionally do with other languages almost never require IDE capabilities.&lt;/p&gt;
&lt;p&gt;Now, with that in mind, here&amp;rsquo;s my Eglot configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((( &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurec-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurescript-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;java-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scala-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-ensure&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-managed-mode&lt;/span&gt;) . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-disable-in-cider&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-disable-in-cider&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-managed-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;progn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;completion-at-point-functions&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;eglot-completion-at-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;xref-backend-functions&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;eglot-xref-backend&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;completion-at-point-functions&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;eglot-completion-at-point&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;xref-backend-functions&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;eglot-xref-backend&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-autoshutdown&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-events-buffer-size&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-extend-to-xref&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-ignored-server-capabilities&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;#39;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hoverProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:documentHighlightProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:documentFormattingProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:documentRangeFormattingProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:documentOnTypeFormattingProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:colorProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:foldingRangeProvider&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot-stay-out-of&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;yasnippet&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same as with &lt;code&gt;lsp-mode&lt;/code&gt; I disable most things I don&amp;rsquo;t need LS to do, like syntax highlighting, formatting, hovering, and folding.
I, personally, don&amp;rsquo;t agree with the decision to put syntax highlighting, formatting and folding into the language server to begin with - requiring to send data to the server in order to do these things is bananas.
The reason it&amp;rsquo;s done like that, I think, is because Microsoft&amp;rsquo;s flagship editor focuses on LSP heavily, and because LSP is their own child, I feel that they simply want to use it, instead of other, often more appropriate solutions.
It&amp;rsquo;s much more sensible to do it with an integrated parser, like Emacs&amp;rsquo; own &lt;code&gt;smie&lt;/code&gt; or now available &lt;code&gt;tree-sitter&lt;/code&gt;, but I digress.&lt;/p&gt;
&lt;h2 id=&#34;problems-and-nuances&#34;&gt;Problems and nuances&lt;/h2&gt;
&lt;p&gt;First and foremost, if the transition was smooth, this section wouldn&amp;rsquo;t be here.
Though I must say, that things are substantially better today than it was several years ago.
Still, I found things that made my workflow a bit harder.&lt;/p&gt;
&lt;h3 id=&#34;jar-archives&#34;&gt;Jar archives&lt;/h3&gt;
&lt;p&gt;Clojure LSP, and Java for that matter, use a special kind of dependency scheme that points to a &lt;code&gt;jar&lt;/code&gt; archive with the dependency source code or class files.
So every time you want to go to the definition of some symbol that came from an external library it&amp;rsquo;s a problem, as Emacs has to do some work to account for that.&lt;/p&gt;
&lt;p&gt;The problem here is that such servers respond to the goto request with a path that mostly depends on the server.
If it&amp;rsquo;s pointing to an archive, it also needs to point to a file, and possibly the position.
&lt;a href=&#34;https://github.com/clojure-lsp/clojure-lsp&#34; target=&#34;_blank&#34;&gt;Clojure-lsp&lt;/a&gt; does it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;jar:file:///.m2/repository/hiccup/hiccup/1.0.5/hiccup-1.0.5.jar!/hiccup/page.clj&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Emacs doesn&amp;rsquo;t understand this kind of path, and tries to create a file instead of going into the archive.
Thankfully, there&amp;rsquo;s a package that fixes that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jarchive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:ensure&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eglot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jarchive-setup&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That problem is no more.
Though it&amp;rsquo;s interesting that &lt;code&gt;lsp-mode&lt;/code&gt; dealt with it on its own, because unlike Eglot, they have separate sub-packages to handle quirks of each language server they support.
When working with Clojure projects this introduced its own problems, as &lt;code&gt;lsp-mode&lt;/code&gt; extracted archives into a &lt;code&gt;.cache&lt;/code&gt; directory, and I often had problems with it becoming stale, as I often switch versions in Git when working on a project.
Switching a version means that dependencies could have changed, but I found that &lt;code&gt;lsp-mode&lt;/code&gt; jumped to a cached file instead of updating it.
It rarely happened, and maybe it was fixed, but I didn&amp;rsquo;t notice.
Hopefully, this won&amp;rsquo;t happen because &lt;code&gt;jarchive&lt;/code&gt; doesn&amp;rsquo;t have cache.&lt;/p&gt;
&lt;h3 id=&#34;xref-completions&#34;&gt;XREF, completions&lt;/h3&gt;
&lt;p&gt;Both &lt;code&gt;lsp-mode&lt;/code&gt; and &lt;code&gt;eglot&lt;/code&gt; provide completion and go to definition facilities via the standard Emacs API.
Completions are provided via the &lt;code&gt;completion-at-point-functions&lt;/code&gt; and goto is done via &lt;code&gt;xref-backend-functions&lt;/code&gt;.
However, &lt;code&gt;lsp-mode&lt;/code&gt; also has additional functions available for calling manually, without going through the Xref interface.
In the end, Xref uses these functions, so it&amp;rsquo;s good for you if you don&amp;rsquo;t want to use Xref, but still want to go to definition.
Here&amp;rsquo;s why that&amp;rsquo;s important, and why I tweak it in the &lt;code&gt;cider-mode-hook&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;ve mentioned, I prefer information from the run-time connection with a REPL when it comes to completion and goto-definition.
It often has updated information, not available statically, such as when you&amp;rsquo;ve required some additional functions in the REPL.
However, this doesn&amp;rsquo;t always work.
For example, when I connect to a remotely running service that runs a network REPL, it often doesn&amp;rsquo;t have any source code information, and REPL can&amp;rsquo;t provide it.
In such cases, I&amp;rsquo;d like to use information from LSP.
And that&amp;rsquo;s where the problems with Eglot begin.&lt;/p&gt;
&lt;p&gt;The way &lt;code&gt;xref-backend-functions&lt;/code&gt; work is as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each function on this hook is called in turn with no arguments, and should return either nil to mean that it is not applicable, or an xref backend, which is a value to be used to dispatch the generic functions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CIDER&amp;rsquo;s backend function checks if there&amp;rsquo;s an nREPL connection for this buffer, and if it is, it returns the backend function.
Which is correct behavior, but then, if the REPL for whatever reason can&amp;rsquo;t provide requested information, Xref bails out and doesn&amp;rsquo;t try the rest of the backends.
Thus, Eglot&amp;rsquo;s backend is never used.&lt;/p&gt;
&lt;p&gt;Backend providers are tried in order, and this order depends on the order in which features are loaded.
I don&amp;rsquo;t enable &lt;code&gt;cider-mode&lt;/code&gt; unless I connect to a REPL, but as seen in the config, &lt;code&gt;eglot-ensure&lt;/code&gt; runs for Clojure major mode automatically.
When I need a REPL, I call &lt;code&gt;cider-jack-in-clj&lt;/code&gt; and it adds the backend to Xref.
Thus, the resulting order is always &lt;code&gt;(cider--xref-backend eglot-xref-backend t)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, if CIDER fails to find a location of the given symbol, with &lt;code&gt;lsp-mode&lt;/code&gt; I could just call &lt;code&gt;lsp-find-definition&lt;/code&gt; manually and bypass Xref.
Can&amp;rsquo;t do so with Eglot.
I know about the &lt;a href=&#34;https://git.sr.ht/~pkal/xref-union&#34; target=&#34;_blank&#34;&gt;xref-union&lt;/a&gt; package, however it doesn&amp;rsquo;t seem to do anything for me.
It adds its own hook into the global value of the &lt;code&gt;xref-backend-functions&lt;/code&gt; and thus its backend is never tried, because of the exact same situation described above.
I guess this package should also clean local hooks fist, or maybe put itself as a local backend in order to work.&lt;/p&gt;
&lt;p&gt;Completions feature a similar problem, though much less annoying.
In &lt;code&gt;lsp-mode&lt;/code&gt; there are functions for enabling and disabling the completion via a minor mode.
With &lt;code&gt;eglot&lt;/code&gt; I can do the same thing in my manipulation &lt;code&gt;completion-at-point-functions&lt;/code&gt;, it&amp;rsquo;s just less user-friendly.
A few notes on why I disable completions:&lt;/p&gt;
&lt;p&gt;Originally, I added this to workaround the problem when both &lt;code&gt;lsp&lt;/code&gt; and &lt;code&gt;cider&lt;/code&gt; run as a part of &lt;code&gt;clojure-mode-hook&lt;/code&gt;.
This results in a different order in which completion backends end up in the &lt;code&gt;completion-at-point-functions&lt;/code&gt; list, and thus one takes precedence over the other.
I since have moved away from running CIDER as a hook, and turn it on explicitly instead as a part of the connection process, and shut it down once no connections left.
This works much better for me, and technically this function should be no longer needed but it isn&amp;rsquo;t the case.&lt;/p&gt;
&lt;p&gt;In reality, their order is kinda arbitrary because of how they&amp;rsquo;re set up.
Once you turn on CIDER, it enables itself automatically for the files in the project you&amp;rsquo;re working with.
Eglot, on the other hand turns itself unconditionally, because it runs in a hook.
Here&amp;rsquo;s how it goes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You open &lt;code&gt;.clj&lt;/code&gt; file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Eglot runs via the &lt;code&gt;clojure-mode-hook&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Buffer local value of the &lt;code&gt;completion-at-point-functions&lt;/code&gt; variable is &lt;code&gt;(eglot-completion-at-point t)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You call &lt;code&gt;cider-jack-in-clj&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Buffer local value of the &lt;code&gt;completion-at-point-functions&lt;/code&gt; variable is &lt;code&gt;(cider-complete-at-point eglot-completion-at-point t)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Which means, CIDER&amp;rsquo;s completion overtakes Eglot&amp;rsquo;s, exactly how I want it to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You open another &lt;code&gt;.clj&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Buffer local value of the &lt;code&gt;completion-at-point-functions&lt;/code&gt; variable for this new buffer is now &lt;code&gt;(eglot-completion-at-point cider-complete-at-point t)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So in the first buffer you get completions from CIDER, but in the second and all other new buffers you get completions from Eglot.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because of that, I had to write the &lt;code&gt;cider-toggle-lsp-completion-maybe&lt;/code&gt; / &lt;code&gt;eglot-disable-in-cider&lt;/code&gt; and set them up so that I get the exact completion backend I want when I use CIDER, and get back LS-powered one once CIDER is disabled.&lt;/p&gt;
&lt;p&gt;I know that this case is probably not as common with other languages, and Clojure is kinda special because it has two separate sources of truth that don&amp;rsquo;t often line up.
When working with a remote application, the source code doesn&amp;rsquo;t always match what&amp;rsquo;s running on the server, because versioning is hard, and sometimes I just forget to do a checkout.
Thus, it&amp;rsquo;s important to get information from the runtime instead, as the statically available information can mismatch actual running code.&lt;/p&gt;
&lt;h3 id=&#34;other-hiccups&#34;&gt;Other hiccups&lt;/h3&gt;
&lt;p&gt;As I&amp;rsquo;ve mentioned, when programming in Clojure, I mostly use LSP for a very few things, as most of the features are backed up by CIDER.
However, there&amp;rsquo;s one thing that CIDER doesn&amp;rsquo;t do as well as &lt;code&gt;clojure-lsp&lt;/code&gt; - finding all references to a given symbol.
There&amp;rsquo;s a separate package called &lt;a href=&#34;https://github.com/clojure-emacs/clj-refactor.el&#34; target=&#34;_blank&#34;&gt;clj-refactor.el&lt;/a&gt; that &lt;a href=&#34;https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-find-usages&#34; target=&#34;_blank&#34;&gt;can&lt;/a&gt; do it, but it almost never works for me, and it is quite slow.
So &lt;code&gt;lsp-find-references&lt;/code&gt; is a very handy feature of &lt;code&gt;lsp-mode&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Eglot has it via the &lt;code&gt;xref-find-references&lt;/code&gt; interface.
However, it suffers from the same thing as completions and goto definition - CIDER&amp;rsquo;s Xref backend takes precedence over Eglot&amp;rsquo;s, and returns much fewer results, because CIDER&amp;rsquo;s implementation of this feature has &lt;a href=&#34;https://metaredux.com/posts/2019/12/11/hard-cider-find-usages.html&#34; target=&#34;_blank&#34;&gt;some issues&lt;/a&gt;.
So a dedicated function, like &lt;code&gt;lsp-find-references&lt;/code&gt; from &lt;code&gt;lsp-mode&lt;/code&gt; would be handy in Eglot too.&lt;/p&gt;
&lt;p&gt;Another thing is that Eglot seem to be blocking Emacs during server initialization.
The &lt;code&gt;clojure-lsp&lt;/code&gt; isn&amp;rsquo;t super slow to start, but it can take some time to initialize.
I don&amp;rsquo;t recall this experience with &lt;code&gt;lsp-mode&lt;/code&gt;, and apparently Eglot has a setting &lt;code&gt;eglot-sync-connect&lt;/code&gt; for choosing how long to wait synchronously for initialization, and then continue in the background if the server isn&amp;rsquo;t initialized by that time.
However, setting it to &lt;code&gt;0&lt;/code&gt; lead to blocking UI completely in my case, so I&amp;rsquo;m not sure what&amp;rsquo;s the deal here.
Maybe it&amp;rsquo;s a bug, but Eglot author &lt;a href=&#34;https://github.com/joaotavora/eglot/issues/466#issuecomment-626351264&#34; target=&#34;_blank&#34;&gt;says that it should not be 0&lt;/a&gt;, so I guess it&amp;rsquo;s not supported or tested properly.
Although, the docstring mentions that it can be set to &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;, so I&amp;rsquo;m not sure what gives.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure what&amp;rsquo;s the problem though, SLY, CIDER, and many other packages I tried that interact with a separate process that takes time to initialize do it without blocking Emacs.
I should follow suite, and make Fennel REPL initialization non-blocking, as right now it is synchronous too.&lt;/p&gt;
&lt;p&gt;And finally, &lt;code&gt;lsp-mode&lt;/code&gt; has its own notion of workspaces/projects, whatever they call them.
Every time you try to initialize a server in a given project, it will ask you if you want to do it and adds this project to a list of all projects where you&amp;rsquo;ve agreed to.
Or, you can then choose to ignore certain projects where you don&amp;rsquo;t want language server to run.&lt;/p&gt;
&lt;p&gt;For instance, in Clojure we often use EDN files to store settings, but in Emacs &lt;code&gt;.edn&lt;/code&gt; is the same as &lt;code&gt;.clj&lt;/code&gt;, i.e. it uses the same &lt;code&gt;clojure-mode&lt;/code&gt; and will trigger language server initialization.
This isn&amp;rsquo;t a problem if you&amp;rsquo;re editing a file within the project, although it is often inconvenient because it paints the screen red as the server doesn&amp;rsquo;t understand that this file contains data and not the code, so it shows tons of unknown symbol-type errors.
But, when such file isn&amp;rsquo;t a part of the project, and sits somewhere else, like for example &lt;code&gt;~/.config/clojure-lsp/config.edn&lt;/code&gt;, it&amp;rsquo;s possible to tell &lt;code&gt;lsp-mode&lt;/code&gt; to don&amp;rsquo;t try to initialize while in the &lt;code&gt;~/.config/clojure-lsp&lt;/code&gt; directory.
I do so for the &lt;code&gt;~/.m2&lt;/code&gt; directory as well, as I don&amp;rsquo;t want language server to be started for each dependency I happened to jump in.
This fine-grained control isn&amp;rsquo;t possible with Eglot as far as I can see - it will try to initialize the sever every time, which is somewhat annoying.
Perhaps it can be done by setting &lt;code&gt;eglot-workspace-configuration&lt;/code&gt; in a project, but I don&amp;rsquo;t understand the documentation for this variable well enough to say for sure.&lt;/p&gt;
&lt;p&gt;None of the issues above are blocking, but some certainly are annoying.
I&amp;rsquo;ll see if I can fix those, but honestly speaking, &lt;code&gt;lsp-mode&lt;/code&gt; still feels like a more complete package for language server support in Emacs.
With just enough configuration it can be made minimum, and it is fast enough for general use with most servers I&amp;rsquo;ve tried.
Additionally, an ability to install the server right from the &lt;code&gt;M-x lsp-install-server&lt;/code&gt; is amazing, and makes updating existing servers trivial.
No need to go to the releases and do the update manually.
I kinda wish Eglot had that, but as far as I understand, being an Emacs core package that would not happen, as none of the core packages I know download stuff from the non-GNU places.
Oh, well.&lt;/p&gt;
&lt;p&gt;So, a quick list of things I&amp;rsquo;d like Eglot to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dedicated functions for finding references, jumping to definitions;&lt;/li&gt;
&lt;li&gt;Minor-mode-like functions for turning Xref and completions on and off on a workspace basis;&lt;/li&gt;
&lt;li&gt;A keymap prefix for mnemonic mapping available commands;&lt;/li&gt;
&lt;li&gt;Ability to ignore certain directories or projects from launching language servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will continue testing Eglot out, and maybe update this post in some time once I arrive at a conclusion on which mode I chose to continue using.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Migrating from LSP-Mode to Eglot&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 09 Sep 2023 23:08:00 +0300</pubDate>
    </item><item>
      <title>Crisis Core Reunion</title>
      <link>https://andreyor.st/posts/2023-09-09-crisis-core-reunion/</link>
      <guid>https://andreyor.st/posts/2023-09-09-crisis-core-reunion/</guid>
      <description>&lt;p&gt;So, I usually don&amp;rsquo;t do game reviews, but this time it&amp;rsquo;s kinda special to me.
I&amp;rsquo;m a bit late to the party as the game come out quite some time ago already, but that&amp;rsquo;s mostly because I didn&amp;rsquo;t plan on getting it.
Honestly, I was too afraid to play this remake, as I cherish my memories with the original game on the PlayStation Portable.
However, my friends at work gave me a copy of this game for Nintendo Switch as a birthday gift, so that&amp;rsquo;s that.
I recently finished the play-through and wanted to write down some thoughts.&lt;/p&gt;
&lt;h2 id=&#34;a-remake&#34;&gt;A remake&lt;/h2&gt;
&lt;p&gt;First things first - I can&amp;rsquo;t consider this game a remaster for a multiple of reasons, even though a lot of sources say it is one.
In my eyes, a remaster is when the developer takes the original game - original sources, models, textures, and enhances the experience, maybe fixes some bugs, does some quality of life improvements, etc.
I feel that this aligns closely to the musical term, where remastering means taking original stems and, well, re-mastering them.&lt;/p&gt;
&lt;p&gt;In case of this release, the engine has obviously changed - Unreal Engine 4 was only in the works when Crisis Core was released, but I doubt PSP could ever run it even if it existed at the time.
It&amp;rsquo;s quite hard to find what engine did the original Crisis Core run on, but probably it was custom-made.
Which means that Reunion is built from the ground up on a different engine.
Perhaps they&amp;rsquo;ve managed to import some old assets, like animations, but I&amp;rsquo;m sure that there was a lot of work done to make Reunion to match as close to original as it does.
And man, how closely does it match the original!&lt;/p&gt;
&lt;p&gt;I still have a PSP lying around, and I compared these two games side by side at various points of the play-through - they line up frame by frame.
Well mostly.
I can&amp;rsquo;t be sure enough, but I think I found some transitions that have been altered, but for the most part, it&amp;rsquo;s the most faithful re-make I have seen in my life.
The other one that comes to mind is Ocarina of Time 3D.
While I never played the original, after completing the game on the 2DS and watching some videos with walk-throughs of the original, I think they&amp;rsquo;re the same animation-wise.
So the Crisis Core remake is on par in that regard.&lt;/p&gt;
&lt;p&gt;I… don&amp;rsquo;t have that much of a problem with the voice acting in this game.
Well, I kinda do, but… we&amp;rsquo;ll get back to this later.
Overall, I&amp;rsquo;m very pleased with this revision of the game.&lt;/p&gt;
&lt;h2 id=&#34;the-original-crisis-core&#34;&gt;The original Crisis Core&lt;/h2&gt;
&lt;p&gt;I got my PSP in 2009 as a birthday gift from my parents.
And I consider this gift one of the most important in my life for a multitude of reasons.
You see, back in the day I was a World of Warcraft &lt;em&gt;addict&lt;/em&gt;.
I was in school, and I found out about WoW pretty late, but I was hooked.&lt;/p&gt;
&lt;p&gt;I played WoW Burning Crusade like a madman - coming from school, playing up until the evening.
This impacted studying a lot, and I noticed that, but I couldn&amp;rsquo;t do anything about it - WoW was too addicting.
So when I got PSP as a birthday gift, I wasn&amp;rsquo;t playing on it too much because I had no games.
That is, until I got my hands on Final Fantasy VII: Crisis Core.&lt;/p&gt;
&lt;p&gt;At first, I played PSP mostly only during long flights over Azeroth or when waiting for someone to go into the dungeon.
But then I noticed that even though my character already arrived at the destination, I kept playing PSP because it actually was way more interesting than WoW.
So, in the end, PSP and Crisis Core helped me drop WoW completely.
I never played it, or any other MMO RPG, ever again.&lt;/p&gt;
&lt;p&gt;This was some of the backstory you probably don&amp;rsquo;t need to know, but I felt like it&amp;rsquo;s important to tell.
I &lt;strong&gt;love&lt;/strong&gt; Crisis Core, and the above is but one of the reasons.&lt;/p&gt;
&lt;p&gt;This game is great, and actually aged pretty well in my opinion.
I&amp;rsquo;ve replayed it several times over the years - it&amp;rsquo;s amazing that my PSP is still alive to this day.
Can&amp;rsquo;t imagine that with the most devices I own today.&lt;/p&gt;
&lt;p&gt;I love this game mostly for its story.
Sure it&amp;rsquo;s simple but it&amp;rsquo;s touching nevertheless.
And actually, I never played the original Final Fantasy VII before I got Crisis Core, so my love doesn&amp;rsquo;t come from nostalgia.
Yes, you can blame me for not playing the original, but I didn&amp;rsquo;t have PlayStation in my childhood - PSP my very first game console.
IIRC FFVII did release on PC, but I didn&amp;rsquo;t know about it.&lt;/p&gt;
&lt;p&gt;What amazes me is how well the characters interact in the original.
English isn&amp;rsquo;t my first language, and in 2009 I couldn&amp;rsquo;t speak in English yet, but I could read it pretty well already.
So I understood the story, often with a dictionary, but thankfully most of it was pretty easy to deduce by what&amp;rsquo;s going on screen.&lt;/p&gt;
&lt;p&gt;What I mean by character interaction is the way they talk.
This game was voiced, and being a Japanese RPG translated to English, you know how often a lot of lines don&amp;rsquo;t really connect.
Localizing a Japanese game is hard, and I think for the Crisis Core, they did a stellar job.
Characters talk very naturally, phrases don&amp;rsquo;t seem to be out of the context or too cheesy or over the top.
And the voice acting is on it - the main characters are all very believable, delivering their lines with passion and power when needed.&lt;/p&gt;
&lt;p&gt;For majority of Japanese media I consume, I prefer original Japanese voices, because translated ones almost never sound like they&amp;rsquo;re belong.
This mostly applies to anime, but also for games.
For instance, Persona 5 with English voices is a horrible experience.
Mostly because of how the dialogues are structured there, and expressions characters make.
Crisis Core is not like that in this regard.
It&amp;rsquo;s dialogues are pretty normal, without much anime grunting, or other quirky stuff, so the English voices fit much nicer.
It varies from game to game though.&lt;/p&gt;
&lt;p&gt;The graphics were also pretty great for a PSP game.
I was amazed by the CGI cutscenes and in-engine ones too.
Later I learned that some in-engine cutscenes were pre-rendered for some reason, but there are maybe like three of them for the whole game.
And this game has a lot of cutscenes, try searching for &amp;ldquo;crisis core full movie&amp;rdquo; on YouTube, it&amp;rsquo;s about 4 hours long.&lt;/p&gt;
&lt;p&gt;The game itself is good too.
Can&amp;rsquo;t say it has the best game feel, a lot of things can feel old today, but overall, for a PSP game it&amp;rsquo;s decent.
I enjoyed it back in 2009, and in later replays.
One such replay My character was at level 60, I completed maybe 70% of side missions, and spent more than 100 hours in game.
Though I never 100% the game, it&amp;rsquo;s not really my thing.&lt;/p&gt;
&lt;p&gt;Then, there&amp;rsquo;s the music.
I learned to play guitar back then, and this game features a lot of beautiful pieces that I was trying to play.
I still can play some of them, even though I don&amp;rsquo;t play guitar as much anymore.
If this doesn&amp;rsquo;t say how much I like this game, I don&amp;rsquo;t know what is.&lt;/p&gt;
&lt;p&gt;This game actually got me crying hard when I finished my first play-through.
And I still tear up, 15 years later, while watching the ending cutscenes.
I truly love this game, and I&amp;rsquo;m glad my parents got me the PSP.&lt;/p&gt;
&lt;h2 id=&#34;the-remake&#34;&gt;The Remake&lt;/h2&gt;
&lt;p&gt;So given everything above, when I learned that they&amp;rsquo;re making a remake, I was shocked and didn&amp;rsquo;t know what to think.
I have played the &lt;a href=&#34;https://youtu.be/8Qlf3b9wa4s?t=50&#34;&gt;&lt;sub&gt;first 5 hours of &lt;/sub&gt;Final Fantasy VII&lt;sub&gt; except 30 hours &lt;/sub&gt;REMAKE&lt;/a&gt; and was kinda disappointed.
The video I linked has some thoughts on the remake I agree with, and so I thought that this is the direction Square Enix decided to take for this series.
At the end of the FFVII Remake they even show a fragment from Crisis Core ending cutscene which was altered and doesn&amp;rsquo;t match with what was in the original game, so when I knew they&amp;rsquo;re remaking Crisis Core I expected them to do what they did with Final Fantasy VII.
And thus I decided I will not play this release, and keep my good memory of the game.&lt;/p&gt;
&lt;p&gt;Then, the videos of the Reunion started to pop up, and I failed to avoid them, so I saw a bit of it, and was indeed disappointed.
The videos featured some early game cutscenes, and voice actors weren&amp;rsquo;t doing the game justice in my opinion.
Turns out, this wasn&amp;rsquo;t just my opinion - lots of fans of the original game were actively discussing new voices, and mostly none of them liked how they&amp;rsquo;ve changed.
This justified not playing the game for me even more.&lt;/p&gt;
&lt;p&gt;Was I wrong?
Well, kinda.&lt;/p&gt;
&lt;p&gt;I already mentioned at the start of this post that the Crisis Core remake is very good, but I want to point out some things.
Also, I would refer to the Crisis Core remake as CC Reunion from this point on, and Final Fantasy VII Remake will be just FFVII Remake.&lt;/p&gt;
&lt;h3 id=&#34;graphics-and-performance&#34;&gt;Graphics and performance&lt;/h3&gt;
&lt;p&gt;After I saw how beautiful the graphics were in the FFVII Remake when it initially released, I immediately thought it would be great if Crisis Core were to be remade with similar graphics.
And while the CC Reunion isn&amp;rsquo;t as beautiful as the Remake, it&amp;rsquo;s close.&lt;/p&gt;
&lt;p&gt;However, I&amp;rsquo;ve noticed that a lot of games today have a weird ghosting effect:&lt;/p&gt;
&lt;div class=&#34;horizontal-gallery&#34;&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-09-09-crisis-core-reunion/2023090900545800-6ED5E421D300F087208CD131AE410033.jpg&#34;
         alt=&#34;Figure 1: The left arm and even some part of the head repeats during camera motion in the limit break animation&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;The left arm and even some part of the head repeats during camera motion in the limit break animation&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-09-09-crisis-core-reunion/2023090900575000-6ED5E421D300F087208CD131AE410033.jpg&#34;
         alt=&#34;Figure 2: In this cutscene, Zack runs toward the camera and to the left of the screen, leaving a trail behind him&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;In this cutscene, Zack runs toward the camera and to the left of the screen, leaving a trail behind him&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;As far as I know, it&amp;rsquo;s caused by TAA which stands for temporal antialiasing, and I don&amp;rsquo;t know who thought it was a good idea to use this technique in games with moving objects.
I can see this effect practically at all times during the game, and it is kinda ruining the experience for me, at least a bit.
Other than that, this game looks solid, especially for running on a Switch - a six-year-old hardware with not the highest specs to begin with.
To be honest, I would actually prefer if it didn&amp;rsquo;t use antialiasing at all, as I don&amp;rsquo;t have any issues with jagged edges in games after playing on PS4 for so many years.
And IMO, jagged edges are a lot easier to forgive than ghosting.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s like motion blur - all games that I play I turn it off when I can, as it makes games more crisp, and doesn&amp;rsquo;t turn the picture into an eye-melting mush every time I turn the camera.
Unfortunately, in the case of CC Reunion, every time something moves over a texture with enough details, a noticeable semi-transparent trail shows up, as shown on the screenshots above.
I thought I would get used to it after some time, but I didn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;But, speaking of performance, the game runs really smoothly, load times are not that long, and I hadn&amp;rsquo;t noticed it using dynamic resolution.
Though, I&amp;rsquo;ve been playing on a couch on a big TV, so I don&amp;rsquo;t think I would notice a difference in resolution that much - it&amp;rsquo;s far more noticeable when you&amp;rsquo;re playing on a PC with the screen right at your face.
Weirdly enough, the pre-rendered CGI cutscenes were lagging more times than I&amp;rsquo;d expected.
I mean, I&amp;rsquo;m assuming it&amp;rsquo;s just a video file played in-game, as it was like this in the original Crisis Core, yet the FPS dropped a few times enough to notice it.
Not sure if that&amp;rsquo;s the Switch&amp;rsquo;s issue or not, as the rest of the game basically runs without any noticeable lag.&lt;/p&gt;
&lt;h3 id=&#34;music-and-sound&#34;&gt;Music and sound&lt;/h3&gt;
&lt;p&gt;I have noticed that the game&amp;rsquo;s music isn&amp;rsquo;t exactly the original music but a re-recording.
Though, I feel like the result is close enough to the original, and it didn&amp;rsquo;t bother me at all.
I&amp;rsquo;m not sure if the ending theme is completely re-recorded or just re-mastered, though.
Perhaps the former, but I wasn&amp;rsquo;t listening closely enough, and I don&amp;rsquo;t remember the original piece all that well already.&lt;/p&gt;
&lt;p&gt;Not much that I can say about the subject, but I didn&amp;rsquo;t want to omit it completely.
I like it more when the original music is kept, but this is also good.&lt;/p&gt;
&lt;h3 id=&#34;story-characters-interactions&#34;&gt;Story, characters, interactions&lt;/h3&gt;
&lt;p&gt;What I do remember is the story.
Perhaps I remember it too well for my own good.
I remember how the lines should go, when the characters say or do something and how they do it.&lt;/p&gt;
&lt;p&gt;And, I gotta say, playing the CC Reunion after I played original for so many times feels extremely uncanny.
I mean literally, Reunion gave me the uncanny valley feeling for maybe the first third of the game.
Here&amp;rsquo;s why:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The game looks a lot like the original - all of the environments are basically the same how I remember them though with a higher graphical fidelity&lt;/li&gt;
&lt;li&gt;The animations are exactly the same.
It&amp;rsquo;s amazing how they managed to do them exactly right.&lt;/li&gt;
&lt;li&gt;The voice acting is different.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This game looks familiar, moves exactly the same how I remember it, yet sounds completely different and it feels extremely weird.
I went and watched some videos where fans put back the original voices on the new in-engine cutscenes, and the uncanny feeling immediately disappears.
But I got accustomed to the new voices pretty quickly.
At first, I started playing with Japanese voices, as tried to shake off this weird feeling, but then I turned back to English voices.
It seems that the actors got better over the course of the recording process.
I mean, listen how Zack says &amp;ldquo;Zack speaking&amp;rdquo; after he gets off the train, and then compare it to later performances near the end of the game.
It&amp;rsquo;s quite different.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t want to talk about voice acting, as I feel that most of the things were already said by the community.
And I do prefer the original voice acting, but the new one is tolerable.
&lt;strong&gt;However&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s one major change to how the story is now perceived - the game is now fully voiced.
In the original, both the CGI and in-engine cutscenes were voiced, but that&amp;rsquo;s it.
The rest of the game was text only.
Talking to NPCs, and even some story elements, were delivered as text.
And, it was fine.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://youtu.be/8Qlf3b9wa4s?t=156&#34; target=&#34;_blank&#34;&gt;Quoting the videogamedunkey channel&lt;/a&gt; again:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s one thing to read a weird dialog, but when you actually hear it, you go: &amp;ldquo;huh?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that&amp;rsquo;s exactly what happens for half of the text-only dialogues from the original.
Paired with the fact that the devs kept the original character animation, it looks hilarious:&lt;/p&gt;
&lt;p&gt;&lt;video controls&gt;&lt;source src=&#34;https://andreyor.st/2023-09-09-crisis-core-reunion/dialogue.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;And there are many examples like this, but I wouldn&amp;rsquo;t blame the voice actors here.
Most dialogues likely weren&amp;rsquo;t meant to be voiced.
Still, this also contributes to the uncanny valley feeling.&lt;/p&gt;
&lt;p&gt;On the other hand, the fact that the in-game dialogues use the same animations is amazing.
In most places, the original animations were expressive and in character.
Re-doing those would further drift this game away from the original, and I would start to question other decisions.&lt;/p&gt;
&lt;p&gt;One thing I don&amp;rsquo;t really get though is why they didn&amp;rsquo;t make characters more like they&amp;rsquo;re in the CGI cutscenes.
I mean, the models are much more detailed now, but more often than not the original models resembled CGI models better.
I don&amp;rsquo;t know how to explain this better, but Zack&amp;rsquo;s face is wider in game than it is in the CGI cutscene.
Maybe that&amp;rsquo;s due to the lighting, though.&lt;/p&gt;
&lt;p&gt;The new designs are OK, and mostly faithful to the original.
Kids are much better than in the original, as there they were extremely low poly.&lt;/p&gt;
&lt;p&gt;The gameplay though is quite different.
If you played the original, you&amp;rsquo;ve probably developed a tactic to avoid unnecessary combat.
In the original, you could do &lt;em&gt;wall-hugging&lt;/em&gt; which means that you basically walk into a wall and slide over it, avoiding triggers that will start the enemy encounter.
This actually still works in the CC Reunion, and it&amp;rsquo;s great, as I can basically complete the game in much the same way I did on PSP.
But it&amp;rsquo;s less necessary now.&lt;/p&gt;
&lt;p&gt;In the original, the combat system was a bit rigid.
The PSP had only so many buttons, lacking a second analog stick, and two additional shoulder buttons.
Thankfully, the Switch has those, and CC Reunion devs decided to revamp the battle controls a bit.&lt;/p&gt;
&lt;p&gt;Now, instead of choosing an action and performing it, which meant that you had to chose basic things like attack, or materia, you can attack at any time, and instead of choosing materia from the ribbon menu, you have quick access via a toggle.
That was a really long sentence without much substance, but I can&amp;rsquo;t explain it better.
The new controls are much better, and I don&amp;rsquo;t miss the original scheme at all.&lt;/p&gt;
&lt;p&gt;Another thing is that in the original, the combat basically was turn-based in disguise.
You selected an action, and Zack was queued to perform it, which could happen after a slight delay.
Enemies were the same in this regard.&lt;/p&gt;
&lt;p&gt;So, for example, you selected a materia that casts a block of ice to fall onto an enemy.
It was marked as &amp;ldquo;next&amp;rdquo; in the UI, and Zack first had to finish any action he was in the middle of, like a dodge.
Then the action was performed automatically.
So even if you were knocked back, Zack would perform the queued action after he gets up by himself.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not like that in the CC Reunion.
The combat is more like in the FFVII Remake, except it retains the Crisis Core specific elements, like Digital Mind Wave.
Speaking of which, now you have to manually execute the limit break, which was automatic in the original.
And I&amp;rsquo;m not sure what I liked more - in the original if you had limit break activated, you were queued invincibility, and it could save you in a lot of situations.
Now it is much harder to avoid damage via a limit break, though it is more reliable.&lt;/p&gt;
&lt;p&gt;I like the new combat system, but I wouldn&amp;rsquo;t say that the old one is bad.
It&amp;rsquo;s just the most dated aspect of the original, but it&amp;rsquo;s still functional.
I definitively engaged into combat more than with the original, but at the end of the game I was still hugging walls, as I didn&amp;rsquo;t play this game for the combat.&lt;/p&gt;
&lt;p&gt;Other than that, the gameplay is pretty much the same, but far less tedious.&lt;/p&gt;
&lt;h2 id=&#34;ending-thoughts&#34;&gt;Ending thoughts&lt;/h2&gt;
&lt;p&gt;I really liked Crisis Core Reunion.
Perhaps because I went into the game with a lot lower expectations, given the fuss around voice acting.
It&amp;rsquo;s a great game, now available to more people than before.
I do wish some things were further improved, but it&amp;rsquo;s nothing serious.&lt;/p&gt;
&lt;p&gt;I do have plans on playing the original Final Fantasy VII on the PlayStation One if I manage to get my hands on one and a CRT TV, as playing it on a modern flat screen will look way too ugly.
Sadly, it&amp;rsquo;s quite hard to find PS1 today, but maybe I&amp;rsquo;ll manage to get the PSX version for PSP I still have and somehow hook it up to a TV.
We&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;As for the FFVII Remake, I don&amp;rsquo;t think I&amp;rsquo;ll play the rest of the games they release.
The Remake changed the story in a way I didn&amp;rsquo;t like.
As far as I know, they will continue re-imagining it, so perhaps I&amp;rsquo;ll pass.&lt;/p&gt;
&lt;p&gt;However, the CC Reunion remake is a good aim for any other remakes that studios want to make.
It&amp;rsquo;s faithful to the original, doesn&amp;rsquo;t change what doesn&amp;rsquo;t need to be changed, and reduces friction where needed.
It does feel like a remaster because of that, and perhaps that&amp;rsquo;s why everyone calls it that.&lt;/p&gt;
&lt;p&gt;And perhaps that what a good remake should be!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Crisis Core Reunion&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 09 Sep 2023 05:51:00 +0300</pubDate>
    </item><item>
      <title>Fennel libraries as single files</title>
      <link>https://andreyor.st/posts/2023-08-27-fennel-libraries-as-single-files/</link>
      <guid>https://andreyor.st/posts/2023-08-27-fennel-libraries-as-single-files/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m pleased to announce that most of my libraries for fennel are now shipped as single files!
It was a long-standing issue with Fennel for me, as there was no clear way to ship both macros and functions in the same file, but after some experimentation, I figured out a way.
After a bit of testing with my new library for &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;asynchronous programming&lt;/a&gt; I can say that it works well enough to be used in most other libraries.
Although the implementation is a bit rough and manual, that&amp;rsquo;s what I&amp;rsquo;ll try to describe here today.&lt;/p&gt;
&lt;p&gt;But first, let&amp;rsquo;s talk modules.
This will be a long post, so buckle up.&lt;/p&gt;
&lt;h2 id=&#34;modules-in-various-programming-languages&#34;&gt;Modules in various programming languages&lt;/h2&gt;
&lt;p&gt;I find it fascinating that a lot of languages have some kind of a module system, yet most of them hide it from the user behind some special keywords and don&amp;rsquo;t allow us to operate on modules as we can do with other objects.
Lua is not one of these languages - its module system is ingenious and yet very simple.
First, let&amp;rsquo;s look at some other languages so you can understand what I&amp;rsquo;m getting at.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s Elixir, a language I sometimes tinker with.
I&amp;rsquo;m using an interactive elixir shell, but it&amp;rsquo;ll be the same even if I were to put this module into a file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(1)&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmodule&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(1)&amp;gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;def&lt;/span&gt; foo(), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(1)&amp;gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;def&lt;/span&gt; bar(), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(1)&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:module&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&amp;lt;70, 79, 82, 49, 0, 0, 5, 180, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 169,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   0, 0, 0, 18, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   105, 110, 102, 111, 95, 95, 10, 97, 116, ...&amp;gt;&amp;gt;, {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt;, 0}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(2)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(3)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;.foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that after the module was defined, we can see a tuple with some keywords, the module symbol, and other stuff.
If we try to examine &lt;code&gt;Lib&lt;/code&gt; in the shell it just prints &lt;code&gt;Lib&lt;/code&gt;.
Yet, we can call the function &lt;code&gt;foo&lt;/code&gt; from this module via the dot syntax: &lt;code&gt;Lib.foo()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we try to inspect what &lt;code&gt;Lib&lt;/code&gt; actually is, we can see that it has a bunch of information but, at least to me, this tells almost nothing of substance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(4)&amp;gt; i &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Term&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Data&lt;/span&gt; type
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Atom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Module&lt;/span&gt; bytecode
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Source&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  iex
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [249975233796634777878553557963106734802]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Compile&lt;/span&gt; options
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:no_spawn_compiler_process&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from_core&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:no_core_prepare&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:no_auto_import&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Description&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Call&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Lib&lt;/span&gt;.module_info() to access metadata.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Raw&lt;/span&gt; representation
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:&amp;#34;Elixir.Lib&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Reference&lt;/span&gt; modules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Module&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Atom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Implemented&lt;/span&gt; protocols
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IEx.Info&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Inspect&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;List.Chars&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;String.Chars&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s look at another language, that I don&amp;rsquo;t often tinker with, but a lot of other people do - Python.
This time I&amp;rsquo;ll put this into a file, as I don&amp;rsquo;t know the shell capabilities of Python, and if it is possible to do stuff like in Elixir.
Here&amp;rsquo;s the same module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# lib.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; ():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; ():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we &lt;code&gt;import&lt;/code&gt; it, we can at least see some indication of what &lt;code&gt;lib&lt;/code&gt; is when we try to inspect it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;module &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&amp;#39;&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;/tmp/lib.py&amp;#39;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; lib.foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What is this &lt;code&gt;&amp;lt;module &#39;lib&#39; from &#39;/tmp/lib.py&#39;&amp;gt;&lt;/code&gt; thing actually?
Python defines different keywords for working with modules, like &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;, and maybe others, as well as a special set of functions to query the module, like &lt;code&gt;dir&lt;/code&gt;.
But the module itself is probably some kind of an object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt;(lib)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;module&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s another language, that I know better than Python or Elixir - Clojure.
In Clojure, similar to Elixir, you can define modules in the REPL, so let&amp;rsquo;s do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib/foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once again, we can see that the namespace is some kind of &lt;code&gt;#namespace[user]&lt;/code&gt; thingy.
If we try to reference the namespace as is in the REPL, we get an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Syntax&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compiling&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*cider-repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog/posts&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:localhost:44133&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:0:0&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;resolve &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;symbol&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, Clojure provides us with a set of &lt;code&gt;ns-*&lt;/code&gt; functions to work with namespaces.
For instance, we can get all interned symbols of the namespace as a map:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-interns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can even go back to the &lt;code&gt;lib&lt;/code&gt; module, define a private function, return to the &lt;code&gt;user&lt;/code&gt; module, and inspect the &lt;code&gt;lib&lt;/code&gt; module again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:private&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/baz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-interns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/baz&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-publics &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yet, modules are something hidden from us, we usually don&amp;rsquo;t operate on them directly.&lt;/p&gt;
&lt;p&gt;So that brings us to Fennel, and therefore Lua.
I will demonstrate things in Fennel just for better clarity, as it provides better inspection capabilities.&lt;/p&gt;
&lt;p&gt;What separates Lua runtime from the rest is that its modules are &lt;em&gt;just tables&lt;/em&gt;.
When we&amp;rsquo;re writing a library, or just a module in our application, the module is just a file on the file system, and at the end of that file the last statement returns a table (or a function):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; lib.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, the table holds references to local functions, and thus the &lt;code&gt;baz&lt;/code&gt; function is completely private.
When we require this module with the &lt;code&gt;require&lt;/code&gt; function it somehow finds the file of this module on disc, loads it, evaluates the top level, and returns the table, which we just then store in a variable, same as any other value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib.foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we try to reference &lt;code&gt;lib&lt;/code&gt; here, we&amp;rsquo;ll see that it is just a table, nothing special:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfecd350&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cff20610&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can check if it has a metatable that hides some module-related trickery, but it&amp;rsquo;s not.
It&amp;rsquo;s a plain ol&amp;rsquo; Lua table.&lt;/p&gt;
&lt;h2 id=&#34;lua-module-system&#34;&gt;Lua module system&lt;/h2&gt;
&lt;p&gt;But Lua doesn&amp;rsquo;t stop there.
I mentioned that &lt;code&gt;require&lt;/code&gt; evaluates the top level, so if we put something like &lt;code&gt;(print &amp;quot;hi!&amp;quot;)&lt;/code&gt; into a module, and require it, we&amp;rsquo;ll see the text being printed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; qux.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qux&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qux&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qux&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s how it looks in the Fennel REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hi!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfe7a1e0&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;./qux.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But if we do a second &lt;code&gt;require&lt;/code&gt; the print won&amp;rsquo;t happen:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfe7a1e0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is because while the modules are plain tables, the &lt;code&gt;require&lt;/code&gt; function is actually smarter than just read+eval.
Module loading process in Lua ensures that modules are only loaded once, and are cached in a special &lt;code&gt;package&lt;/code&gt; table.&lt;/p&gt;
&lt;h3 id=&#34;package-dot-loaded-caching-module-definitions&#34;&gt;&lt;code&gt;package.loaded&lt;/code&gt; - caching module definitions&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.loaded.qux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qux&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfe7a1e0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So each time we call &lt;code&gt;(require :something)&lt;/code&gt; it first looks if &lt;code&gt;package.loaded.something&lt;/code&gt; exists, and if it is, it just returns the value from there.
This way, we can unload any module, just by setting a key in the &lt;code&gt;package.loaded&lt;/code&gt; to &lt;code&gt;nil&lt;/code&gt;, and then &lt;code&gt;require&lt;/code&gt; will re-evaluate our module.
Fennel actually provides a REPL command for that, called &lt;code&gt;reload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, it&amp;rsquo;s still not that simple.
Lua&amp;rsquo;s &lt;code&gt;require&lt;/code&gt; is actually extensible.
If the module was not found in the &lt;code&gt;package.loaded&lt;/code&gt; the next place &lt;code&gt;require&lt;/code&gt; checks is &lt;code&gt;package.preload&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;package-dot-preload-preloading-modules-via-anonymous-functions&#34;&gt;&lt;code&gt;package.preload&lt;/code&gt; - preloading modules via anonymous functions&lt;/h3&gt;
&lt;p&gt;This table stores modules in a similar way, except instead of storing tables, it stores functions that when called will load a module.&lt;/p&gt;
&lt;p&gt;We can utilize this in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.my-lib&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;loading my-lib&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hello&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;!&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hello&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hello&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4d4a23d50&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.my-lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4d4a23d50&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve created a function in that table, that when called will signal that the module is loaded, define a local function, and return a table, referencing that function.
So it&amp;rsquo;s essentially the same as the file approach, except it is stored in a function, which execution is delayed until someone tries to &lt;code&gt;require&lt;/code&gt; the module.
Lua was meant to be able to work in filesystem-less environments, and this is one of the solutions for storing libraries.&lt;/p&gt;
&lt;p&gt;When we &lt;code&gt;require&lt;/code&gt; the &lt;code&gt;my-lib&lt;/code&gt; module, we see the &lt;code&gt;loading my-lib&lt;/code&gt; message, but instead of providing a second value with the file from where the module was read, the value is &lt;code&gt;:preload:&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:my-lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loading&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-lib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hello&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4d4a4ecf0&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:preload:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This indicates that the library was indeed loaded from the &lt;code&gt;package.preload&lt;/code&gt; table.
We can then use it as normal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:my-lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-lib.hello&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Bob&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;hi Bob!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This already gives us some power, and Fennel utilizes &lt;code&gt;package.preload&lt;/code&gt; to provide fully self-contained AOT-compiled Lua files that can be shipped without any external dependencies.
Yet, there&amp;rsquo;s a final step in this system that we can discuss.&lt;/p&gt;
&lt;h3 id=&#34;package-dot-searchers-extending-the-module-system&#34;&gt;&lt;code&gt;package.searchers&lt;/code&gt; - extending the module system&lt;/h3&gt;
&lt;p&gt;If the module was found neither in the &lt;code&gt;package.loaded&lt;/code&gt; nor in the &lt;code&gt;package.preload&lt;/code&gt;, the &lt;code&gt;require&lt;/code&gt; function starts using special &lt;code&gt;package.searchers&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.searchers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b930&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b970&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b9b0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cfc8b9f0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55f4cff32450&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s another table in the &lt;code&gt;package&lt;/code&gt; table, that stores a list of functions, that will try to find and load the given module by their own means.
Let&amp;rsquo;s write our own:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.searchers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;searching &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; with a custom searcher\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loader&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bye&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bye %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bye&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loader&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This searcher function in our case will work for any module regardless of its existence, so by doing this we kinda broke the loading mechanism.
Still, this might be useful in some sandboxing scenarios.
Alternatively, this mechanism can be used if the environment you run Lua in doesn&amp;rsquo;t have a real file system, so finding a module requires some trickery, and thus you can extend the general &lt;code&gt;require&lt;/code&gt; mechanism.
What our function does is not as complicated - it&amp;rsquo;s similar to what we did in the &lt;code&gt;preload&lt;/code&gt; example, except what makes it different is that it basically allows us to do whatever we want before this &lt;code&gt;loader&lt;/code&gt; function is given back to the runtime.&lt;/p&gt;
&lt;p&gt;We can see it works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asdf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searching&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;asdf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;custom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55ec3e592ae0&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;asdf&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:qwer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searching&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;qwer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;custom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;searcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55ec3e529460&amp;gt;&lt;/span&gt;}	&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;qwer&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:asdf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bye&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55ec3e592ae0&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that it obeys the same caching rules.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;package.searchers&lt;/code&gt; table is the sole reason why Fennel works as seamlessly as it is.
Setting up Fennel&amp;rsquo;s package searcher means that when we&amp;rsquo;re trying to &lt;code&gt;require&lt;/code&gt; some &lt;code&gt;module&lt;/code&gt; if there is a &lt;code&gt;module.fnl&lt;/code&gt; file on the &lt;code&gt;FENNEL_PATH&lt;/code&gt;, Fennel will compile this module, and then load it as a normal Lua module.
If you want to implement your own Lua-based language, this is definitely the place to embed your compiler.&lt;/p&gt;
&lt;p&gt;Now that you have an idea of how modules work in Lua, let&amp;rsquo;s discuss the main topic of this post - single-file Fennel libraries, and complications related to it.&lt;/p&gt;
&lt;h2 id=&#34;fennel-libraries-with-macros&#34;&gt;Fennel libraries with macros&lt;/h2&gt;
&lt;p&gt;A library in Fennel obeys the exact same rules as a Lua library, except the Fennel compiler adds some steps to the whole process of library loading.
As I explained in the &lt;a href=&#34;#package-dot-searchers-extending-the-module-system&#34;&gt;searchers topic&lt;/a&gt;, the compiler is invoked on the module file before it is given to the Lua runtime.
This means, that when we&amp;rsquo;re loading a Fennel file, it first gets compiled to Lua, and only then it is loaded.
This works well up until we introduce compile-time features into our modules - mainly macros.&lt;/p&gt;
&lt;p&gt;If we look back at Clojure and Elixir examples, I didn&amp;rsquo;t use macros in the modules - let&amp;rsquo;s fix this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;test &lt;/span&gt;&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;] `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-not &lt;/span&gt;~&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;test &lt;/span&gt;~@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/my-do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Syntax&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compiling&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*cider-repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog/posts&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:localhost:44133&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:0:0&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Can&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;t&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro&lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns-interns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;baz&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/baz&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/bar&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/unless&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; #&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;lib/foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we try to take a value of the macro, we get an error, as macros are a compile-time construct.
Yet, it is referenced in the &lt;code&gt;ns-intern&lt;/code&gt; as a var.
And we can go back to the &lt;code&gt;user&lt;/code&gt; module, and use our macro from there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;in-ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;namespace&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib/unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Elixir, it is similar, as you also can provide a macro in your module, and upon requiring the module you can use a macro from it.
Here&amp;rsquo;s an example macro from the &lt;a href=&#34;https://elixir-lang.org/getting-started/meta/macros.html#our-first-macro&#34; target=&#34;_blank&#34;&gt;docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(2)&amp;gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmodule&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;   &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt;(clause, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: expression) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;     &lt;span style=&#34;font-weight:bold&#34;&gt;quote&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;       &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt;(!&lt;span style=&#34;font-weight:bold&#34;&gt;unquote&lt;/span&gt;(clause), &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;font-weight:bold&#34;&gt;unquote&lt;/span&gt;(expression))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;     &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt;   &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...(2)&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:module&lt;/span&gt;, &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;&amp;lt;70, 79, 82, 49, 0, 0, 6, 72, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 191,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   0, 0, 0, 20, 13, 69, 108, 105, 120, 105, 114, 46, 85, 110, 108, 101, 115,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   115, 8, 95, 95, 105, 110, 102, 111, 95, 95, ...&amp;gt;&amp;gt;, {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;, 2}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(3)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.&lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;this should never be printed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;UndefinedFunctionError&lt;/span&gt;) function &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.macro_unless/2 is undefined &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; private.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;However&lt;/span&gt;, there is a macro with the same name &lt;span style=&#34;font-weight:bold&#34;&gt;and&lt;/span&gt; arity.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Be&lt;/span&gt; sure to &lt;span style=&#34;font-weight:bold&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; you intend to invoke this macro
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.&lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:ok&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    iex:3: (file)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except, we can&amp;rsquo;t use this macro right away - unlike in Clojure, we need to &lt;code&gt;require&lt;/code&gt; the module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(3)&amp;gt; &lt;span style=&#34;font-weight:bold&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(4)&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt;.&lt;span style=&#34;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;do&lt;/span&gt;: &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because Elixir&amp;rsquo;s macros are entirely Elixir&amp;rsquo;s concept, BEAM knows nothing about them, and thus you can use them only in Elixir, and it explains why the shell requires some additional steps.
Perhaps these can be automated, as Clojure can do it without any additional &lt;code&gt;require&lt;/code&gt; calls, but I don&amp;rsquo;t know for sure how it is done in Clojure or in Elixir.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m bringing Elixir and Clojure here because both languages are hosted on their respective runtimes - Erlang&amp;rsquo;s BEAM and JVM.
Fennel is similarly hosted on Lua, but on the other hand, is different from these two when it comes to macros.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s add the &lt;code&gt;unless&lt;/code&gt; macro to the &lt;code&gt;lib.fnl&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; lib.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Trying to load this module, however, will result in a compile error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;./lib.fnl&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:5:27&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Compile&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tried&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reference&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;without&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calling&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Try&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;renaming&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;so&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conflict&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locals.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can&amp;rsquo;t simply export our macro alongside our functions.
What should we do then?&lt;/p&gt;
&lt;p&gt;The fennel language &lt;a href=&#34;https://fennel-lang.org/reference#macros&#34; target=&#34;_blank&#34;&gt;reference&lt;/a&gt; suggests that macros can&amp;rsquo;t be referenced and exported alongside functions
And that &lt;code&gt;macro&lt;/code&gt; is supposed to be used only as file-local macros, and thus these can&amp;rsquo;t be exported.
Additionally to that, when writing &lt;a href=&#34;https://fennel-lang.org/reference#macros-define-several-macros&#34; target=&#34;_blank&#34;&gt;macros&lt;/a&gt;, we can&amp;rsquo;t access any surrounding code.
The reference section then says that in order to export macros we can put them into a separate module and use &lt;code&gt;import-macros&lt;/code&gt; to import them to the arbitrary code.&lt;/p&gt;
&lt;p&gt;The whole macro system in Fennel is not as advanced as in other lisps or as in Elixir, but it gets the job done, it just requires some squats to be done.&lt;/p&gt;
&lt;h3 id=&#34;macro-modules&#34;&gt;Macro modules&lt;/h3&gt;
&lt;p&gt;A macro module is exactly the same as an ordinary Fennel module - it shares the same file extension, same syntax, but is meant to be used in conjunction with &lt;code&gt;import-macros&lt;/code&gt; or &lt;code&gt;require-macros&lt;/code&gt; specials.
To write a macro module we can simply put our &lt;code&gt;unless&lt;/code&gt; macro into a separate file, replacing &lt;code&gt;macro&lt;/code&gt; with &lt;code&gt;fn&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; unless.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test&lt;/span&gt;) &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s right, in Fennel, macros are ordinary functions running in a compiler environment, and now we actually can export them as an ordinary table.
The compiler environment defines additional functions that we can use in macros, such as &lt;code&gt;quote&lt;/code&gt; and &lt;code&gt;unquote&lt;/code&gt; which we&amp;rsquo;re using here in the forms of &lt;code&gt;`&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt;.
Now we can require this module with &lt;code&gt;import-macros&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless.unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should never be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless.unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;false&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;should&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;be&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;printed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s also another special that can import macros from a module: &lt;code&gt;require-macros&lt;/code&gt;.
Unlike &lt;code&gt;import-macros&lt;/code&gt; it doesn&amp;rsquo;t put macros in a binding, instead, it pollutes the current scope with all of the macros from the module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;this should be printed&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So &lt;code&gt;(import-macros name module)&lt;/code&gt; is much like &lt;code&gt;(local name (require module))&lt;/code&gt; but for macro modules, and it uses &lt;code&gt;require-macros&lt;/code&gt; underneath.&lt;/p&gt;
&lt;h3 id=&#34;import-macros-and-require&#34;&gt;&lt;code&gt;import-macros&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Speaking of the relationship between &lt;code&gt;import-macros&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt;, they indeed work similarly.
Fennel&amp;rsquo;s developers understood that Lua&amp;rsquo;s module system is very flexible and decided to make a similar interface for macros.&lt;/p&gt;
&lt;p&gt;You couldn&amp;rsquo;t see it, but in the previous example, when I called &lt;code&gt;require-macros&lt;/code&gt; on the &lt;code&gt;unless&lt;/code&gt; module again, it didn&amp;rsquo;t re-read the module from disk.
Instead, it used the same technique of caching, much like &lt;code&gt;package.loaded&lt;/code&gt; but instead, it uses &lt;code&gt;fennel.macro-loaded&lt;/code&gt; to store macros.
We can see that by requiring Fennel in the REPL and inspecting the table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.macro-loaded&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56224adc40a0&amp;gt;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can even do the same thing as with the &lt;code&gt;package.loaded&lt;/code&gt;, and set the &lt;code&gt;unless&lt;/code&gt; module to &lt;code&gt;nil&lt;/code&gt; with &lt;code&gt;(set fennel.macro-loaded.unless nil)&lt;/code&gt;
If we then add some side-effecting code, like &lt;code&gt;(print &amp;quot;macros!&amp;quot;)&lt;/code&gt; to the module, and require it again, we&amp;rsquo;ll see that Fennel will re-read our module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.macro-loaded.unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macros!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Unless&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:unless&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But only once, much like with ordinary &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Similarly to Lua, Fennel provides its own table with searcher functions for macros:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.macro-searchers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56224ac5a740&amp;gt;&lt;/span&gt; #&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x56224ac5a7f0&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the system is extremely similar, the only thing it lacks is something akin to &lt;code&gt;package.preload&lt;/code&gt; but for macros.
With that in mind let me introduce you to the library problem.&lt;/p&gt;
&lt;h3 id=&#34;the-library-problem&#34;&gt;The library problem&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s imagine, we want to write a library that provides you with a lot of functions, and with some convenience macros that remove some boilerplate.
In reality, almost anything can be done without macros, but macros are great for writing code that you don&amp;rsquo;t want to write yourself.
So let&amp;rsquo;s say we want to add polymorphic dispatch to Fennel by adding multimethods.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s write the functions first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; {}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__call&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.get-method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The idea is simple.
We create an object with the function &lt;code&gt;multi&lt;/code&gt; and give it a &lt;code&gt;dispatch-fn&lt;/code&gt; - the function it will invoke with the arguments to determine what method it needs to call.
If there is a method, it will be called with the same arguments as the &lt;code&gt;dispatch-fn&lt;/code&gt; functions.
I also provided convenience functions that provide some abstraction over the inner implementation of the multimethod object.
Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.multi&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny lion&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny runs away&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion bunny&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion eats bunny&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion lion&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lion2&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lions fight&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny bunny&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bunny2&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunnies mate&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny runs away&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bunny&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lion eats bunny&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I opted for a simple example, where I just get the &lt;code&gt;type&lt;/code&gt; field of each object and concatenate them into a string.
Then we dispatch on that string.&lt;/p&gt;
&lt;p&gt;The library is now complete, but it&amp;rsquo;s a bit tedious to type all of these anonymous functions every time, let&amp;rsquo;s add an interface similar to how Clojure does this.
We&amp;rsquo;ll add two macros &lt;code&gt;defmulti&lt;/code&gt;, which given a name and a dispatch fn will create a local variable by itself, and &lt;code&gt;defmethod&lt;/code&gt; which will act the same as &lt;code&gt;add-method&lt;/code&gt; except it will construct the anonymous function for us.
We start by creating the macro module:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We already have the multimethod itself, so let&amp;rsquo;s try our &lt;code&gt;defmethod&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethod-macros&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship rock&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_rock&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship.name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; sinks&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa sinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works, but did you notice the problem?
Let&amp;rsquo;s try this again, but instead, let&amp;rsquo;s call our library something else in the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethod-macros&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unknown&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:2:?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Compile&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unknown&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;identifier&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking into the macroexpansion of &lt;code&gt;defumilti&lt;/code&gt; we see that it does exactly what we told it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;macrodebug &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult.multi&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Except, the &lt;code&gt;mult&lt;/code&gt; is nowhere to be found.&lt;/p&gt;
&lt;p&gt;So, here&amp;rsquo;s the problem - we need to reuse functions from our function module in the macro module.
Unfortunately, there&amp;rsquo;s literally no way to do it without making some assumptions about the module name.
Instead of using available binding in the macro, we can require the library because it&amp;rsquo;s cached:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this change, everything starts working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethod-macros&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship rock&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_rock&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship.name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; sinks&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa sinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But there&amp;rsquo;s another problem - what if the user of our library doesn&amp;rsquo;t like that the module file name is &lt;code&gt;multimethods.fnl&lt;/code&gt; and wants to rename it?
Suppose they already have their own multimethods module and want to try out ours alongside it, so they rename it to &lt;code&gt;aorst-multimethods.fnl&lt;/code&gt;.
Required macros will suddenly stop working because in our macros we hardcoded the &lt;code&gt;multimethods&lt;/code&gt; module name.&lt;/p&gt;
&lt;h4 id=&#34;init-dot-fnl-and-init-macros-dot-fnl&#34;&gt;&lt;code&gt;init.fnl&lt;/code&gt; and &lt;code&gt;init-macros.fnl&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;One solution to this problem is to use Lua&amp;rsquo;s other hidden module mechanic, related to how the searchers work.&lt;/p&gt;
&lt;p&gt;In Lua, we can load a file by giving &lt;code&gt;require&lt;/code&gt; a module name that matches that file, like &lt;code&gt;require &amp;quot;foo&amp;quot;&lt;/code&gt; will probably load the &lt;code&gt;foo.lua&lt;/code&gt; file.
However, we can also load a directory in the same way - instead of creating &lt;code&gt;foo.lua&lt;/code&gt; we can create a directory &lt;code&gt;foo&lt;/code&gt; and write the contents of &lt;code&gt;foo.lua&lt;/code&gt; into &lt;code&gt;foo/init.lua&lt;/code&gt;.
Then, calling &lt;code&gt;require &amp;quot;foo&amp;quot;&lt;/code&gt; will seamlessly load code from &lt;code&gt;init.lua&lt;/code&gt;, but it will look like we&amp;rsquo;re loaded a directory.&lt;/p&gt;
&lt;p&gt;Fennel supports the same thing for ordinary modules with &lt;code&gt;init.fnl&lt;/code&gt;, but in addition to that, it also supports this for macro modules with &lt;code&gt;init-macros.fnl&lt;/code&gt;.
We can re-implement our multimethod library this way, but we&amp;rsquo;ll change how we require the library in the macros:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; multimethods-lib/init-macros.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for relative require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This trick is called relative-require.
It&amp;rsquo;s quite common in Lua, but I decided to use it when I was trying to ship huge libraries with lots of macros and inner modules.&lt;/p&gt;
&lt;p&gt;When the module is loaded, Lua passes the module name to the module as an argument.
This &lt;code&gt;(local lib-module ...)&lt;/code&gt; captures it in the &lt;code&gt;lib-module&lt;/code&gt; variable, and then we can refer to it in our macros.
If we now look at what our macros expand to, we&amp;rsquo;ll see that they use the module name correctly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods-lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multimethods-lib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;macrodebug &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods_2_auto&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;multimethods-lib&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods_2_auto.multi&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now our macros are unbound from the library name itself.
However, shipping library in this way is not that great.
For example, here&amp;rsquo;s how one of my libraries that uses this technique looks if you peek into the library root:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── CHANGELOG.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── CODE_OF_CONDUCT.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── CONTRIBUTING.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── doc/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── fennel-test/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── impl/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── init.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── init-macros.fnl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── Makefile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── tests/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Basically, it&amp;rsquo;s the project&amp;rsquo;s root, and if you want to use this library, the easiest way is to just git-clone the project and require it.
But it means that there are lots of unrelated files, and there&amp;rsquo;s no way to know what files are related unless the project has some kind of manifest, which is not the case for Fennel projects.
It would be much better if you could just grab only the &lt;code&gt;init.fnl&lt;/code&gt; file, name it however you want, and require both macros and functions from it.&lt;/p&gt;
&lt;h4 id=&#34;require-as-include&#34;&gt;Require-as-include&lt;/h4&gt;
&lt;p&gt;Fennel has a feature that can do almost that.
For multi-file libraries, we can AOT compile all of the Fennel code into Lua, and the compiler will inject all of the dependencies in an interesting way.
It does so by tracking what modules we &lt;code&gt;require&lt;/code&gt; and splicing them into the code by using &lt;code&gt;package.preload&lt;/code&gt; trick I&amp;rsquo;ve described way earlier in this post:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#39;s foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:some-lib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-foo&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-lib.foo&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:my-foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my-foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we call &lt;code&gt;fennel --require-as-include -c my-lib.fnl&lt;/code&gt;, we&amp;rsquo;ll get the following code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; some_lib
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;package.preload[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#34;&lt;/span&gt;] = package.preload[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#34;&lt;/span&gt;] &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#39;s foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {foo = foo}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;some_lib = require(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-lib&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;my_foo&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; some_lib.foo()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;my-foo&amp;#34;&lt;/span&gt;] = my_foo}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the whole module definition of &lt;code&gt;some-lib&lt;/code&gt; was included in the file as an entry in the &lt;code&gt;package.preload&lt;/code&gt;.
In the later code, it is required and used as normal.&lt;/p&gt;
&lt;p&gt;However, this doesn&amp;rsquo;t work with macros, as there is no &lt;code&gt;fennel.macro-preloaded&lt;/code&gt; or something similar.
And for a long enough time, I wasn&amp;rsquo;t sure if it was possible to mimic this behavior at compile time.
But then I remembered that we indeed have the module name at compile time, as clearly shown in the relative-require example.&lt;/p&gt;
&lt;h3 id=&#34;mimicking-preload-behavior-for-macros&#34;&gt;Mimicking preload behavior for macros&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s what I came up with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-compiler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.multi&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mmethods#.add-method&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;macro-loaded&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; {}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__call&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self.get-method&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi.remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatch-val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:multi&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:add-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:get-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:remove-method&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove-method&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can require our library and macros from the same module, and it doesn&amp;rsquo;t have to be a directory!
Here&amp;rsquo;s how it looks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mm&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:combined-multimethods&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:combined-multimethods&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmulti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.type&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defmethod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship rock&amp;#34;&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_rock&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ship.name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; sinks&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;interact&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ship&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa&amp;#34;&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rock&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wasa sinks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, it&amp;rsquo;s a combination of techniques, but what exactly is &lt;code&gt;eval-compiler&lt;/code&gt; doing here?&lt;/p&gt;
&lt;p&gt;If you look closely at &lt;code&gt;evel-compiler&lt;/code&gt; body, you&amp;rsquo;ll see that instead of exporting the table at the end of the scope we simply set it to the &lt;code&gt;macro-loaded&lt;/code&gt; table.
We use the module name which was set to &lt;code&gt;combined-multimethods&lt;/code&gt; when the module was required, and thus the &lt;code&gt;macro-loaded.combined-multimethods&lt;/code&gt; now stores the table with macro definitions.
Then, when &lt;code&gt;require-macros&lt;/code&gt; looks up the macro module &lt;code&gt;combined-multimethods&lt;/code&gt;, it sees that it was already loaded, and simply returns it without trying to find a file with these macros.
Alternatively, we could define a macro-searcher that, given a specific &lt;code&gt;module-name&lt;/code&gt; would do the same thing, loading macros while avoiding trying to find a file, but it&amp;rsquo;s more work for almost no benefit over what we have here already.&lt;/p&gt;
&lt;h4 id=&#34;preprocessor-as-include&#34;&gt;Preprocessor-as-include&lt;/h4&gt;
&lt;p&gt;There&amp;rsquo;s still a problem though.
What if we want to write a library, that uses another library, that uses macros in this way?&lt;/p&gt;
&lt;p&gt;One such example is my &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;cljlib&lt;/a&gt; library I keep re-implementing every few months or so.
In that library I also wanted to ship macros and functions in the same module, but here&amp;rsquo;s a problem - this library depends on other libraries, namely &lt;a href=&#34;https://gitlab.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy-seq&lt;/a&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;itable&lt;/a&gt;.
While &lt;code&gt;itable&lt;/code&gt; doesn&amp;rsquo;t provide any macros, &lt;code&gt;lazy-seq&lt;/code&gt; does, and &lt;code&gt;cljlib&lt;/code&gt; re-uses these macros.&lt;/p&gt;
&lt;p&gt;Before some recent changes I made to both &lt;code&gt;lazy-seq&lt;/code&gt; and &lt;code&gt;cljlib&lt;/code&gt; you had to fiddle with &lt;code&gt;FENNEL_PATH&lt;/code&gt; and &lt;code&gt;FENNEL_MACRO_PATH&lt;/code&gt; in order to use &lt;code&gt;cljlib&lt;/code&gt;, and you had to check out the full repository with submodules.
I feel like this is way too much work for most people, and I don&amp;rsquo;t want anyone to suffer that much, so I changed it to use the trick above and embedded other libraries into it by manually writing the &lt;code&gt;package.preload&lt;/code&gt; trick instead of relying on &lt;code&gt;--require-as-include&lt;/code&gt; flag.
Here&amp;rsquo;s how it looks in the &lt;code&gt;src/cljlib.fnl&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; itable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.itable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.itable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;;###include itable/src/itable.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.preload.lazy-seq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;;###include lazy-seq/lazy-seq.fnl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; cljlib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-compiler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; macros ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; functions ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These &lt;code&gt;;;;###include path&lt;/code&gt; comments are nothing special from the perspective of Fennel, but I made a small &lt;code&gt;build.fnl&lt;/code&gt; script for the library that takes care of them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spit-lib&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; patching compile-time variable used to store macro module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; name because when loafing the combined file it will always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; equal the main module and will break macros in vendored&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; libraries.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%(local lib%-name %(or %.%.%. (.*)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(local lib-name (or &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;./cljlib.fnl&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:w&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;src/cljlib.fnl&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lines&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:match&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;;;###include (.*)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spit-lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cljlib&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is meant to be used only for development, the library is pre-built and ready for anyone to grab.
What&amp;rsquo;s interesting about this script is that it also patches the library it includes.
This was a pain to figure out.&lt;/p&gt;
&lt;p&gt;You see, in the &lt;code&gt;lazy-seq&lt;/code&gt; library I&amp;rsquo;m using the same &lt;code&gt;eval-compiler&lt;/code&gt; trick, and it in turn uses the &lt;code&gt;(local lib-name (or ... :lazy-seq))&lt;/code&gt; trick.
However, when this library is spliced into our main file as is, when we load this file as &lt;code&gt;(require :cljlib)&lt;/code&gt;, the &lt;code&gt;...&lt;/code&gt; becomes &lt;code&gt;&amp;quot;cljlib&amp;quot;&lt;/code&gt;, and the &lt;code&gt;lazy-seq&lt;/code&gt; library, included in this file will write its macros into &lt;code&gt;macro-loaded.cljlib&lt;/code&gt; instead of supposed &lt;code&gt;macro-loaded.lazy-seq&lt;/code&gt;.
This can&amp;rsquo;t be worked around, as this happens way before &lt;code&gt;package.preload.lazy-seq&lt;/code&gt; runs, so the &lt;code&gt;...&lt;/code&gt; provided by the function in that table is never used by &lt;code&gt;eval-compiler&lt;/code&gt;.
The only way to delay the &lt;code&gt;eval-compiler&lt;/code&gt; is to put it into the file or use the searcher that will evaluate this block of code by itself which is way too tricky.&lt;/p&gt;
&lt;p&gt;So I made a hack, that while splicing the library code scans for any occurrences of the &lt;code&gt;(local lib-name (or ...&lt;/code&gt; pattern, and replaces it with the name used in the &lt;code&gt;or&lt;/code&gt; expression, without checking &lt;code&gt;...&lt;/code&gt;.
This way, the &lt;code&gt;(local lib-name (or ... :lazy-seq))&lt;/code&gt; becomes &lt;code&gt;(local lib-name (or :lazy-seq))&lt;/code&gt; in the final version of &lt;code&gt;cljlib.fnl&lt;/code&gt;.
Of course, it is extremely finicky, as even an introduction of a newline between &lt;code&gt;lib-name&lt;/code&gt; and &lt;code&gt;(or ...)&lt;/code&gt; expression will break this.
Changing &lt;code&gt;lib-name&lt;/code&gt; to something else will also break this down.&lt;/p&gt;
&lt;p&gt;But even with this kind of monkey-patching it works well enough, as I control what code goes in both libraries, and the user doesn&amp;rsquo;t need to think about it at all.
All that is needed to do is just to grab the &lt;code&gt;cljlib.fnl&lt;/code&gt; from the repo root and put it into the project.
I&amp;rsquo;ve updated &lt;a href=&#34;https://gitlab.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;Fenneldoc&lt;/a&gt; to use the newer version of &lt;code&gt;cljlib&lt;/code&gt; and was pleased to see that it still works.&lt;/p&gt;
&lt;h2 id=&#34;fixing-macros-in-fennel&#34;&gt;Fixing macros in Fennel&lt;/h2&gt;
&lt;p&gt;Even with the ability to ship macros in the same file as functions, I find it weird that Fennel&amp;rsquo;s macro system has all sorts of other limitations.&lt;/p&gt;
&lt;p&gt;Firstly, the inability to use functions defined alongside macros is really bad.
This is one of the reasons we have to do all these squats with relative-require stuff and require the library itself from the macro.
Which in turn makes us more error-prone, if some weird environment will not set the module args (&lt;code&gt;...&lt;/code&gt;) properly.&lt;/p&gt;
&lt;p&gt;Another thing is that macros can&amp;rsquo;t use other macros unless they&amp;rsquo;re defined in a separate module, or in the &lt;code&gt;eval-compiler&lt;/code&gt; trick I was featuring in this post.
If you define a macro with the &lt;code&gt;macro&lt;/code&gt; special, it must be self-contained.
Otherwise, you have to move it somewhere.
I mean, it&amp;rsquo;s weird that Fennel has a proper implementation of macros sitting in the compiler, but for some reason &lt;code&gt;macro&lt;/code&gt; and &lt;code&gt;macros&lt;/code&gt; specials don&amp;rsquo;t use it.&lt;/p&gt;
&lt;p&gt;What I think would fix all this mess is this:&lt;/p&gt;
&lt;p&gt;First, we need to ditch macro modules completely.
They&amp;rsquo;re inferior to ordinary fennel modules and only make things complicated.&lt;/p&gt;
&lt;p&gt;Next, we need to make it so the &lt;code&gt;macro&lt;/code&gt; special sets the macro in the &lt;code&gt;macro-loaded&lt;/code&gt; entry of the current module, much like I manually do in the &lt;code&gt;eval-compiler&lt;/code&gt; block.&lt;/p&gt;
&lt;p&gt;And lastly, when compiling the module to Lua, just load the module at compile time as a whole!
This way not only macros will be able to use other macros, but they&amp;rsquo;ll also be able to use other ordinary functions at compile time!&lt;/p&gt;
&lt;p&gt;The only problem left is how to make it so the generated code can use definitions from the library.
And I think I know the way, and it&amp;rsquo;s similar to how Clojure handles things.&lt;/p&gt;
&lt;p&gt;So basically, same as in Clojure, macros can only use public definitions.
What this means is that these definitions are in the &lt;code&gt;packagr.loaded&lt;/code&gt; by the time we&amp;rsquo;ve required the library.
Therefore, the backquote can safely fully qualify any unqualified symbol in the calling position!&lt;/p&gt;
&lt;p&gt;In other words, the macro &lt;code&gt;bar&lt;/code&gt; from this file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After macroexpanding will become:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;require-macros &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:lib&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;macrodebug &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;1 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package.loaded.lib.foo&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And will work just fine, as it can reach &lt;code&gt;foo&lt;/code&gt;, as it is already in the &lt;code&gt;package.loaded&lt;/code&gt; by that time.
Which is similar to what Clojure does:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;] `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt; ~&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macroexpand &lt;/span&gt;&amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bar&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 2 3)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user/foo&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;1 2 3))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And as the final change, we need to make that the &lt;code&gt;fennel.searcher&lt;/code&gt; properly sets up &lt;code&gt;macro-loaded&lt;/code&gt; in order to ditch the awkward &lt;code&gt;(doto :lib require)&lt;/code&gt; thing.&lt;/p&gt;
&lt;p&gt;Anyhow, that&amp;rsquo;s all I got for today.
I know that I&amp;rsquo;m writing a lot of devlog posts about my small game dev marathon, so I try to write some posts in-between so that my blog doesn&amp;rsquo;t become too focused on one topic.
Hope that this was an interesting read!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Fennel libraries as single files&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 27 Aug 2023 20:45:00 +0300</pubDate>
    </item><item>
      <title>Game2 W4/4</title>
      <link>https://andreyor.st/posts/2023-08-25-game2-w44/</link>
      <guid>https://andreyor.st/posts/2023-08-25-game2-w44/</guid>
      <description>&lt;p&gt;Well, It&amp;rsquo;s unfortunate, but I couldn&amp;rsquo;t make the game in these 4 weeks.
August is just too much of a pain in terms of the amount of different events - maybe even the busiest month in the whole year, for me personally.
Judging by the commit history, I was able to work only for 11 days out of the 28 days given to me by the challenge - and I tried to do at least some work every day and commit everything I did.
I&amp;rsquo;m saying 11 days, but maybe 5 of these were in this last week.&lt;/p&gt;
&lt;p&gt;This last week was all about level generation and, unfortunately, I failed at it.
I was trying to implement the &lt;a href=&#34;https://andreyor.st/posts/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/&#34;&gt;Wave Function Collapse&lt;/a&gt; algorithm in Lua and for some weird reason, it didn&amp;rsquo;t work.
After three failed attempts, I decided to cheat.
My idea was to go and port my ClojureScript version to Fennel form by form and compile it to Lua after it works.
However, it didn&amp;rsquo;t work as well, no idea why.
For some reason, some branches in my code are just never visited at all, although I did everything the same way, and implemented missing pieces from Clojure&amp;rsquo;s standard library for this code to work.
At least it terminated, but instead generated a complete gibberish:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (wfc (gen_world 9 9) coast)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[&amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟫&amp;#34;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is supposed to look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user&amp;gt; (wfc (gen-world 9 9) coast)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[&amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟫&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟩&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34; &amp;#34;🟦&amp;#34;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This reminded me of the importance of data structures and their properties I keep forgetting when programming in Clojure.
Because in Clojure it&amp;rsquo;s just the thing you have, so you don&amp;rsquo;t think much about it.&lt;/p&gt;
&lt;p&gt;You see, Clojure has 4 main data structures, baked up with literals: list &lt;code&gt;(a, b)&lt;/code&gt;, map &lt;code&gt;{k1 a, k2 b}&lt;/code&gt;, vector &lt;code&gt;[a, b]&lt;/code&gt;, and set &lt;code&gt;#{a, b}&lt;/code&gt;.
Each of these has its own set of properties, for example, lists are only fast to add elements at the front, and vectors are fast to add elements to the tail.
Maps are mostly like Lua&amp;rsquo;s tables, and sets are like maps in the way that they can only store unique elements, and are indexed like a map but iterated like a list.&lt;/p&gt;
&lt;p&gt;In my ClojureScript implementation of the WFC algorithm, I used all these data structures and relied on their behavior.
For example, the superposition for a cell after the world&amp;rsquo;s initialization is a set of all possible values for the cell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I used maps to store the recipe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The map itself stores maps with sets that are later used in the algorithm.
Other data structures are at play for other parts of the whole process, but I&amp;rsquo;m not going to touch them here.&lt;/p&gt;
&lt;p&gt;Lua on the other hand has only one collection type - the table.
It can serve as a vector, to which you can add elements at the tail, and you can use them as hash tables, where there can only be a single instance of a given key.
Sets can also be represented if we just use a table where keys are elements and values are the same elements or something like &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; superposition = {[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is actually what the &amp;ldquo;Programming in Lua&amp;rdquo; book &lt;a href=&#34;http://www.lua.org/pil/11.5.html&#34; target=&#34;_blank&#34;&gt;suggests&lt;/a&gt;.
The recipe then looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- Sorry, not sorry for formatting - all these brackets on separate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- lines take a stupidly big amount of vertical space&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]={up={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         down={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         left={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         right={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;}},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]={up={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         down={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         left={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         right={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;}},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]={up={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         down={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         left={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         right={[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- also, the table syntax is just horrible - why square brackets are&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- needed around strings for keys? Why can&amp;#39;t we write {&amp;#34;foo bar&amp;#34;=&amp;#34;baz&amp;#34;}?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- And why can we write {foo=&amp;#34;bar&amp;#34;}? Why variable foo is not the same&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- foo when used in the table? Why foo is now a string?  The syntax is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- too smart for its own good.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, here&amp;rsquo;s the problem - how do we tell apart sets from key-value tables?
We can write some predicates, like &lt;code&gt;is_set&lt;/code&gt; that either check that all values are &lt;code&gt;true&lt;/code&gt;, or create a constructor function that will add a hidden &lt;code&gt;__index&lt;/code&gt; metatable with a &lt;code&gt;is_set&lt;/code&gt; key set to true, but it&amp;rsquo;s all pretty janky, in my opinion at least.
A proper data structure should have its own syntax literal and a set of functions to check the type.
Lua doesn&amp;rsquo;t even give you the ability to distinguish sequential tables from associative ones&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
I don&amp;rsquo;t think that Clojure&amp;rsquo;s choice of &lt;code&gt;#{}&lt;/code&gt; for sets is great, but it&amp;rsquo;s a lot better than nothing.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s also another issue with our implementation of sets - iteration support.
In Clojure, you can iterate over any type of data structure, and it will actually do it in a meaningful way.&lt;/p&gt;
&lt;p&gt;If you try to iterate over a list, vector, or set - it will just iterate over the elements:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map identity &lt;/span&gt;&amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map identity &lt;/span&gt;[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map identity &lt;/span&gt;#{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the case of a set the order is not determined, so the order of results is arbitrary.
If you try to iterate over a map though, it&amp;rsquo;s a bit different:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map identity &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:c&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:e&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same as for the set, the order is arbitrary, but you can see that the elements in the list are vectors.
That&amp;rsquo;s right, when we iterate over the map we get back vectors, containing the key and its value, which we can then use in the function that we iterate with.&lt;/p&gt;
&lt;p&gt;You may be thinking: &amp;ldquo;Well, that&amp;rsquo;s the same as what &lt;code&gt;pairs&lt;/code&gt; does in Lua&amp;rdquo; but it&amp;rsquo;s not.
Unlike what I have shown to you, &lt;code&gt;pairs&lt;/code&gt; will &lt;strong&gt;always&lt;/strong&gt; return the key and value, even for vectors.
Yes, in the case of a vector, the key will be an index, and we can pretty much ignore it most of the time, but what about our sets?
In the case of our set implementation, the key is actually the value we&amp;rsquo;re looking for, because the value is just &lt;code&gt;true&lt;/code&gt;.
So no, implementing sets as tables that store &lt;code&gt;true&lt;/code&gt; as a value is a no-go for most use cases, we have to store the value both as a key and a value in a set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; superposition = {[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;, [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I digress.&lt;/p&gt;
&lt;p&gt;Another, very important property of Clojure&amp;rsquo;s data structures is that they&amp;rsquo;re both immutable and persistent.
This means that whatever we do with the vector doesn&amp;rsquo;t actually change the vector - it returns a new vector that shares the unchanged part of the structure with the old one plus new stuff.
Clojure author went to great lengths to make this process fast and reliable.&lt;/p&gt;
&lt;p&gt;I used this heavily in the CLJS version of the algorithm.
Perhaps too heavily, but it&amp;rsquo;s a different topic.
What it gave me though is the ability to change the world without mutating the original world, so every step of the algorithm actually produced a new world, and I could trace it back to the very beginning if I wanted to.
It is not as fast as the mutation-based approach but is much more sane to work with and debug.&lt;/p&gt;
&lt;p&gt;My first implementation of the algorithm in Lua, however, was mutating the world.
Not only it is hard to debug, Lua makes it harder because you can&amp;rsquo;t view the data structure you&amp;rsquo;re working with.
You probably don&amp;rsquo;t remember it, but I made a &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;complete rewrite&lt;/a&gt; of the pretty printer for the Fennel language, and I did it mostly because the original one produced the representation that was hard to read due to indentation going all over the place.
Well, guess what, Lua doesn&amp;rsquo;t have its own pretty printer whatsoever.
You have to write your own or import some library that does it for you, which is not feasible with TIC-80, as its screen resolution is too small to comfortably read anything, especially huge tables that contain lots of elements, like the world I was trying to generate.
Can you feel my frustration?&lt;/p&gt;
&lt;p&gt;Then I made a hacky &lt;code&gt;deepcopy&lt;/code&gt; function (another part that lacks from Lua because &lt;em&gt;tables&lt;/em&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;) to at least get a copy-on-write type of immutability in Lua.
This slowed down things to the point that it was useless for the sizes of worlds I wanted to construct.
And it didn&amp;rsquo;t fix the problem, so it was somewhere else.
I wasn&amp;rsquo;t ready to re-implement the whole thing again, so I stopped here.&lt;/p&gt;
&lt;p&gt;Another thing I keep forgetting is how great Clojure&amp;rsquo;s standard library for manipulating collections is.
There are all sorts of operations on sets, you can transform maps, iterate on anything, rename keys, etc., etc.
Lua has a very rudimentary library for tables, that can&amp;rsquo;t do almost anything.
Sure, there are libraries like &lt;a href=&#34;https://github.com/lunarmodules/Penlight&#34; target=&#34;_blank&#34;&gt;Penlight&lt;/a&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, and &lt;a href=&#34;https://github.com/lua-stdlib/lua-stdlib&#34; target=&#34;_blank&#34;&gt;lua-stdlib&lt;/a&gt; that could help with that, and I made a &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;port&lt;/a&gt; of Clojure&amp;rsquo;s core namespace to Fennel (and therefore Lua) but again - TIC-80 makes it hard to use these libraries.
So, no, Lua isn&amp;rsquo;t great at manipulating data structures, and porting Clojure code to it is a pain.
What did I expect?
Well, I&amp;rsquo;ve ported all the functions I used in my CLJS WFC implementation, things like &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;keep&lt;/code&gt;, &lt;code&gt;map-indexed&lt;/code&gt;, &lt;code&gt;get-in&lt;/code&gt;, &lt;code&gt;assoc-in&lt;/code&gt;, etc., but there were still problems with how to iterate over tables, as there is no sequence abstraction in Lua, and it&amp;rsquo;s hard to make it properly.
I tried multiple times before, and the best I got was my &lt;a href=&#34;https://gitlab.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy sequence&lt;/a&gt; library for Fennel, but even there I took some shortcuts regarding the situation with tables that have both associative and array parts.
Sorry Lua fans, but combined data structures like that are stupid.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m writing this a bit early, as there are clearly some more days until the end of this week, but then again, I won&amp;rsquo;t have time to do any work neither this evening, nor tomorrow, or the day after that.
It&amp;rsquo;s a shame though, I don&amp;rsquo;t want to abandon this roguelike idea, and maybe I&amp;rsquo;ll get back to it after the challenge ends.
Or maybe not, I don&amp;rsquo;t know.
I will have another chance to make a top-down game, but probably without an isometric projection.&lt;/p&gt;
&lt;p&gt;Looking back on the development process for this game I can see that choosing the isometric projection was probably the wrong decision.
First, I struggled with the projection itself, then with the projection of screen coordinates back to the world coordinates.
Halfway through I ditched the isometric projection and started drawing stuff without it, in hopes that I will just enable it back when the world generation is ready.
But then the world generation was a problem.
I didn&amp;rsquo;t even get to work on enemies, items, menus, and so on.
Well, a roguelike is a lot more involved than a simple platformer, so it is expected that it takes more time to do stuff, but I didn&amp;rsquo;t have that time unfortunately.&lt;/p&gt;
&lt;p&gt;Lua isn&amp;rsquo;t the one to blame for all these problems though.
While I did get some frustrations with its syntax, overall the experience wasn&amp;rsquo;t that bad.
However, I will not probably use it for upcoming projects.
The &lt;code&gt;lua-mode&lt;/code&gt; package for Emacs is in a rough shape - there is no pairing support for &lt;code&gt;do end&lt;/code&gt; keywords, like in &lt;code&gt;sh-mode&lt;/code&gt; or &lt;code&gt;ruby-mode&lt;/code&gt;.
Indentation is extremely slow and often unpredictable.&lt;/p&gt;
&lt;p&gt;The next game on the list is a Card game but I&amp;rsquo;m not in the mood for that at all, so I&amp;rsquo;m going to change this and make a side-scrolling shoot-em-up kind of game.
It should be much easier, and with all of the frustration built up over the last month, this is probably just what I need.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I know that the distinction isn&amp;rsquo;t possible because the data structure combines both sequential and associative parts in one package, but at least Lua could give us some predicates that would check if the associative part has any values and if the sequential part is not empty.
This way we would be able to detect if the table we&amp;rsquo;re looking at only has the array part, or only has the associative part which is much better than nothing.
It can be done in Lua but it is slow and often unreliable.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;It is hard to properly implement deep copying because of metatables.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;I keep forgetting its name and every single time I have to search for it as &amp;ldquo;lua batteries included&amp;rdquo; to only find a reddit post with a link to the repo that just lists lots of libraries for Lua.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game2 W4/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 25 Aug 2023 18:35:00 +0300</pubDate>
    </item><item>
      <title>Game2 W3/4</title>
      <link>https://andreyor.st/posts/2023-08-20-game2-w34/</link>
      <guid>https://andreyor.st/posts/2023-08-20-game2-w34/</guid>
      <description>&lt;p&gt;Why is it the third week that I finally gain any interest in actually working on the game?
Now, when I think of it, this may be the whole reason I couldn&amp;rsquo;t get into game dev during earlier attempts in the past years.
I consider myself an OK programmer and I know a bit of math that is required for making basic games, so I doubt it was due to a lack of knowledge.
Maybe it is that by the third week, there are some actual results that produce enough stimulation to my brain making it act as a feedback loop that amplifies the feeling until it burns out, and I just never stuck enough for that to trigger before.
Well, I experienced something like that during my first game jam, but not so much after when I made further attempts at this.
I guess forcing myself was the right decision.&lt;/p&gt;
&lt;p&gt;Anyways.
I mostly figured out the map problem I talked about in the previous post and the whole thing started moving, like, literally.
I ported the camera into this project and made a really basic way of moving in the world and it already feels like a game:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2023-08-20-game2-w34/camera.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This, however, didn&amp;rsquo;t go as smoothly, as the previous time.
I&amp;rsquo;m still figuring out the quirks, as my rendering pipeline is kinda weird.
You see, in the previous post, I made it so the tiles, used to build up a level, are baked into the cart&amp;rsquo;s map memory block.
This way I don&amp;rsquo;t have to recalculate projections of every floor tile on every tic and can do culling, drawing only what&amp;rsquo;s really is on screen, plus some extra boundary for smooth camera movement.
However, it means that when projecting to the level I need to account for the map offset, somehow.
This turned out to be a bit more challenging than I thought.&lt;/p&gt;
&lt;p&gt;For now, I put that problem aside, as I can always get back to it when I have more complex levels, and I needed to figure out the opposite of what I was doing in the previous post - project screen coordinates back to the world&amp;rsquo;s coordinates.
Because this game is meant to be a roguelike I&amp;rsquo;m going to use the mouse in this game for movement with some automatic path-finding.
Path-finding will have to wait though.&lt;/p&gt;
&lt;p&gt;After a bit of trial and error, I got it working:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-20-game2-w34/movement.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;But again, this only works either for the static camera position, or a specific level geometry because of all the magic numbers spread through my code.
I didn&amp;rsquo;t have much time this week, only the first half, so I basically did nothing starting from Wednesday.
While it&amp;rsquo;s a shame, Starting next week I&amp;rsquo;m on vacation and hopefully will be able to spend much more time on the game and finish it in time.
Or at least get all of the mechanics working, and publish it as another demo.&lt;/p&gt;
&lt;p&gt;So, next up - world generation.
I looked at some interesting algorithms for dungeon generation in 2D roguelike games and while many of them are interesting in their own way, I don&amp;rsquo;t want to complicate things that much.
So instead, I turned to my older project - wave function collapse.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going a bit ahead of myself here as I haven&amp;rsquo;t started working on this yet, but I thought that it will be a nice and organic way to generate small, fixed-size levels.
But a plain WFC won&amp;rsquo;t work for me, so I made some adjustments.
The basic idea is to choose some points on the finite grid and assign them to specific elements.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a janky drawing with all of this in place:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-20-game2-w34/generation.jpg&#34; width=&#34;50%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;These objects in the drawing are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Four rotations of room exits, connected to a floor tile, corridor tile, and two wall tiles;&lt;/li&gt;
&lt;li&gt;level entry and level exit, connected to 4 floor tiles at each side;&lt;/li&gt;
&lt;li&gt;spawn tile, also connected to 4 floor tiles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To evenly distribute things in the level, I decided to divide the world into four sectors shown above as a gray grid.
Each sector can have only so many objects to hold, with the exception of entries and exits - these are shared across all segments and there can be only one of each.&lt;/p&gt;
&lt;p&gt;Once objects are in place, the actual WFC takes over and fills the world.
The blue walls on the image and black corridor paths will be generated by WFC, and because it will not pick empty tiles by itself, I suppose isolated rooms won&amp;rsquo;t appear.
The nice part is that the rules can be extremely simple, as there are basically 4 types of tiles used, unlike my previous project.
Of course, I can add variety later.
But that&amp;rsquo;s the topic for the next week.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game2 W3/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 20 Aug 2023 21:02:00 +0300</pubDate>
    </item><item>
      <title>Game2 W2/4</title>
      <link>https://andreyor.st/posts/2023-08-13-game2-w24/</link>
      <guid>https://andreyor.st/posts/2023-08-13-game2-w24/</guid>
      <description>&lt;p&gt;Didn&amp;rsquo;t have much progress on the Game2 this week.
Mostly worked on some additional assets, and rendering the world into an isometric grid.&lt;/p&gt;
&lt;p&gt;In the last post, I mentioned that it is very hard to come up with floor tiles that leave enough colors for things to be seen.
I didn&amp;rsquo;t mention it in the previous post, but here are the original tiles I drew for the game to represent the floor and walls:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-13-game2-w24/old-floor-wall-tiles.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;That&amp;rsquo;s right, I didn&amp;rsquo;t plan on using isometry originally.
However, this looked blunt and there wasn&amp;rsquo;t enough space to add any decoration.
I could, of course, bump the floor tile size to 4 tiles, but it started to look way too big.
Isometry, however, looks decent in my opinion:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-13-game2-w24/Screenshot_20230812_112859_Pixel%20Studio.jpg&#34; width=&#34;50%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The only problem though is how do I draw this?&lt;/p&gt;
&lt;p&gt;I created a sample level as a two-dimensional array and a simple projection function to project the world&amp;rsquo;s coordinates to screen coordinates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; level = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,RW,RW,RW,RW,RW,RW,RW,RW,RW},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, LW,F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, RW,F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {LW,F, F, F, F, F, F, F, F, F},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isometric_project&lt;/span&gt; (x, y, w, h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (x*8)+(y*-8), (x*4)+(y*4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;LW&lt;/code&gt; is Left Wall, &lt;code&gt;RW&lt;/code&gt; is a right wall, and &lt;code&gt;F&lt;/code&gt; is floor.
All are objects with a single &lt;code&gt;draw&lt;/code&gt; method, that knows how to draw the tiles.&lt;/p&gt;
&lt;p&gt;I then drew this to the screen with a simple nested loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;load_level&lt;/span&gt; (level)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ox,oy=x,y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; offx,offy=120,8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; y=1,#level &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; x=1,#level[y] &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t=level[y][x]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table&amp;#34;&lt;/span&gt; == type(t) &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; mx,my=isometric_project(x-1,y-1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        t.draw(mx+ox+offx,my+offy+oy)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives me the correct result, albeit there&amp;rsquo;s no special code to draw this with composite tiles, so walls correctly intersect with ordinary tiles:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-13-game2-w24/wip-render.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;While this works, there&amp;rsquo;s a problem.
As can be seen in the &lt;code&gt;level&lt;/code&gt; array, there are only two kinds of walls - left and right ones.
Ultimately, I want to bake this layout into the map, so I can just call &lt;code&gt;map&lt;/code&gt; to render the whole level, and get camera culling as I did in the previous game.
And it isn&amp;rsquo;t easy to see the problem with the isometric grid from the app where I drew these tiles, so let me bring a non-isometric grid in the engine:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-13-game2-w24/wip-render-w-grid.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;There are some tiles that right now only take up half of a tile vertically, and some walls are drawn with two tiles and some with three tiles.
This means, that I can&amp;rsquo;t just bake this on a tile-by-tile basis into the map with &lt;code&gt;mset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a closer look at the problem in case you didn&amp;rsquo;t see it:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-13-game2-w24/grid-problem.png&#34; width=&#34;50%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I, however, only used the two-tiled walls in this picture (marked with a red grid), so because of that I can&amp;rsquo;t bake this into a map, as the tiles I used don&amp;rsquo;t match the map grid.
Still thinking about how to approach this, as there&amp;rsquo;s also a second problem - entities should be able to stay behind the walls, so in reality I can&amp;rsquo;t bake this all to the map, probably only the floor tiles, and I will have to draw the walls separately.
Or via a second map call.
I mean, I &lt;em&gt;can&lt;/em&gt; draw it just like I do now, but this nested for loop bothers me way too much.
When I will add entities and have bigger levels I fear this will become really slow.&lt;/p&gt;
&lt;p&gt;There are probably ways of doing this easied than what I try to do, but this is just how I roll.&lt;/p&gt;
&lt;p&gt;Additionally, I drew even more items, and I decided that for every single-tile item I will draw a bigger one for the equipment menu:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-13-game2-w24/more-sprites.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Hopefully, I will figure out the isometry and have time to implement this.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game2 W2/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 13 Aug 2023 10:23:00 +0300</pubDate>
    </item><item>
      <title>Game2 W1/4</title>
      <link>https://andreyor.st/posts/2023-08-06-game2-w14/</link>
      <guid>https://andreyor.st/posts/2023-08-06-game2-w14/</guid>
      <description>&lt;p&gt;First week, second game!&lt;/p&gt;
&lt;p&gt;This time I opted to go with plain Lua.
Don&amp;rsquo;t get me wrong, I like Fennel, but I wanted to get a bit more authentic experience.
Apart from having a nicer standard library, Fennel doesn&amp;rsquo;t add anything to the &lt;em&gt;table&lt;/em&gt; in the case of the TIC-80 environment.
E.g. there&amp;rsquo;s no REPL that I can attach to from the editor and change code around, and there&amp;rsquo;s no real need for macros.&lt;/p&gt;
&lt;p&gt;Plus, I&amp;rsquo;d like to remind myself why I appreciate Fennel so much, as things like pattern matching, table comprehensions, and other Fennel-specific features are not available in Lua.
On the other hand, Lua is simpler, and the code being run is what you&amp;rsquo;d expect, not something that a compiler produced.
If you dared to look into the Lua version of the cart that I published at the end of the last post on the Game1 topic, you know that it looks horrific at times.&lt;/p&gt;
&lt;p&gt;So Lua it is.
TIC-80 actually provides even more languages, namely Ruby, JavaScript, MoonScript, Scheme, Squirrel, Wren, Janet, Python, and even plain WASM, I may try to use some of these.
I haven&amp;rsquo;t decided on future games yet though.&lt;/p&gt;
&lt;p&gt;Speaking of languages - why so many?
This is probably the single thing I dislike about TIC-80 and like more in PICO-8 - the latter is only programmable in a subset of Lua.
If I&amp;rsquo;m being honest, I would rather only leave Lua in TIC and ditched everything else - it&amp;rsquo;s much more authentic this way.
Even if that would mean losing direct Fennel support which, while a shame, is OK - we can always AOT.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve quickly gone through the development log, and it seems that the author is pretty generous with adding new languages to the project.
MoonScript was added first (probably), as far as I can see.
There&amp;rsquo;s a still &lt;a href=&#34;https://github.com/nesbox/TIC-80/issues/1471&#34; target=&#34;_blank&#34;&gt;open request&lt;/a&gt; for Nimscript, whatever it is.
Don&amp;rsquo;t get me wrong, the project is nothing less than amazing, I just think less is more when it comes to things like this.
But I digress.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve spent most of my first week thinking about the game and what would it evolve around.
After a bit of consideration, I decided to make a cyber-based roguelike, because there are already way too many traditional magic-based roguelikes.
So instead of a mighty artifact in my game, the character will search for the mighty neural chip that can do any kind of calculations instantly.
I can also try focusing on range battles, which should give a fresh spin on classic roguelikes too.&lt;/p&gt;
&lt;p&gt;I started working on graphics, but then life told me that I should not do anything this week and I had a power outage for quite some time.
Anyhow, this is what I got so far:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-08-06-game2-w14/sprites.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I also tried making some floor tiles, and once again I feel the limitations of the palette - it&amp;rsquo;s so hard to come up with floor tiles that will make other sprites properly visible.
Maybe I&amp;rsquo;ll add outlines if I will not find a clever solution.&lt;/p&gt;
&lt;p&gt;One such solution might be to divide the palette into two smaller palettes.
In other words, the first 8 colors can be used for interactable objects, and the last 8 for the scenery.
Maybe I&amp;rsquo;ll try that too.
It&amp;rsquo;s even more restrictive, though.&lt;/p&gt;
&lt;p&gt;Unfortunately, I don&amp;rsquo;t think I followed my own word, and the first week went pretty unproductive regarding Game2.
And yes, I will name all of these games like that, sorry!
I did some work on my async library for Fennel, as I found some bugs in it though.
But I&amp;rsquo;ll bring the pace up the next week for sure!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game2 W1/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 06 Aug 2023 23:04:00 +0300</pubDate>
    </item><item>
      <title>async.fnl enchancements</title>
      <link>https://andreyor.st/posts/2023-08-02-asyncfnl-enchancements/</link>
      <guid>https://andreyor.st/posts/2023-08-02-asyncfnl-enchancements/</guid>
      <description>&lt;p&gt;Lately, I&amp;rsquo;ve been working on &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt; in my spare time and realized that the previous code that I used to schedule timers was terrible.
Well, &lt;em&gt;realized&lt;/em&gt; isn&amp;rsquo;t an appropriate word here, because I knew it back when I first implemented it, I just didn&amp;rsquo;t bother to make it better until I had a fully working library.
So, a few weeks ago I had an idea on how to make things both more efficient and prevent excessive CPU usage when there&amp;rsquo;s no need to.&lt;/p&gt;
&lt;h2 id=&#34;lua-debug-hooks&#34;&gt;Lua &lt;code&gt;debug&lt;/code&gt; hooks&lt;/h2&gt;
&lt;p&gt;Lua comes with the &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#6.10&#34; target=&#34;_blank&#34;&gt;debug&lt;/a&gt; library.
This library provides a set of relatively low-level facilities to implement your own debugger, and one such things are hooks.&lt;/p&gt;
&lt;p&gt;All hook manipulations are done with &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-debug.sethook&#34; target=&#34;_blank&#34;&gt;debug.sethook&lt;/a&gt; and &lt;a href=&#34;https://www.lua.org/manual/5.4/manual.html#pdf-debug.gethook&#34; target=&#34;_blank&#34;&gt;debug.gethook&lt;/a&gt; functions - one to set/unset the hook, and the other to retrieve existing hook, respectively.
A hook is a simple Lua function, that accepts the &lt;code&gt;event&lt;/code&gt; which triggered it.
Lua gives us five types of events we can check for in our hook: &lt;code&gt;&amp;quot;call&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;tail call&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;return&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;line&amp;quot;&lt;/code&gt;, and &lt;code&gt;&amp;quot;count&amp;quot;&lt;/code&gt;, but we&amp;rsquo;re only really interested in one - the &lt;code&gt;&amp;quot;count&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But before we discuss hooks, I&amp;rsquo;d like to do a small detour into how my old async library handled things.
It will both allow you to understand why I decided to move away from the old implementation, and how we can use hooks to achieve similar facilities later.
Feel free to &lt;a href=&#34;#hooks--the-less-wrong-way&#34;&gt;skip&lt;/a&gt; if you&amp;rsquo;re not interested.&lt;/p&gt;
&lt;h3 id=&#34;scheduler&#34;&gt;Scheduler&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s how asynchronous threads were handled in an older implementation of my other async library.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The library had a special scheduler object, that kept track of all tasks to be run.&lt;/li&gt;
&lt;li&gt;Each task that wanted to stop itself for some time is called the &lt;code&gt;async.park&lt;/code&gt; function, usually indirectly via something like &lt;code&gt;async.take&lt;/code&gt; or &lt;code&gt;async.put&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;additionally, If a task wants to sleep for some time, it can call &lt;code&gt;async.sleep&lt;/code&gt;, which, when called on the asynchronous thread, parks it with a special condition, and tells the scheduler that this task should not be touched for the specified amount of time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then, once the internal &lt;code&gt;scheduler.run&lt;/code&gt; is called, all tasks are examined, and the shortest amount of sleep is chosen, if any.
&lt;ul&gt;
&lt;li&gt;If there are tasks that aren&amp;rsquo;t sleeping, the system resumes those tasks;&lt;/li&gt;
&lt;li&gt;If, however, all tasks want to sleep, the system determines the minimum amount of time it needs to sleep and puts the main thread to sleep.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once all tasks ran, the &lt;code&gt;scheduler.sleep&lt;/code&gt; exits unless the user requested it to run until all tasks are fully complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This worked reasonably fine but required someone to call the &lt;code&gt;scheduler.run&lt;/code&gt; periodically.
The library tried to make it transparent for the program, as any operation that created threads, pushed or polled for values, and so on, called &lt;code&gt;shceduler.run&lt;/code&gt; internally, to give an illusion that the system actually works in parallel.
Thus, if you made a blocking take on some channel, the &lt;code&gt;scheduler&lt;/code&gt; would run until that channel is ready to return the value (though, this might never happen).&lt;/p&gt;
&lt;p&gt;The main downside of this was that the whole system depends on a central scheduling mechanism, and the more tasks you have spawned, the less performant the scheduler becomes.
For example, here&amp;rsquo;s a function, that tracks the amount of time it took for value to be put to a channel and then read back in another thread:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel-async.async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bench&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that loops putting the values one by one, and tracks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; the time when it completed each put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that takes values, and measures the amount of time it took&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for value to be transferred.  Loops for more until the channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; is closed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; waits til both threads are done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s call it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6.0796737670898e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.1205673217773e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.8848648071289e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7.8678131103516e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.1062316894531e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7.8678131103516e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.6941299438477e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pretty fast.
Now, let&amp;rsquo;s add &lt;em&gt;a few&lt;/em&gt; tasks that will immediately park because there&amp;rsquo;s no one to produce values, and will simply exist in a scheduler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; create 10000 channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.chan&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; spawn 10000 tasks waiting on these channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async.take&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This seemingly innocent &lt;code&gt;each&lt;/code&gt; loop took a whopping 148 seconds to execute on my machine!
It takes so much time because the library re-runs the scheduler over an ever-increasing number of tasks on every single call to &lt;code&gt;async&lt;/code&gt;.
So, it&amp;rsquo;s basically O(n²) loop even though it looks like O(n).&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s call our function again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.033475875854492
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.040903806686401
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.044415950775146
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.043467998504639
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039731979370117
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039532899856567
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039582014083862
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039039134979248
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039515972137451
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.039596080780029
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, even though all of the threads were parked, and our &lt;code&gt;bench&lt;/code&gt; function doesn&amp;rsquo;t interact with any of them directly, its execution was slowed down &lt;strong&gt;severely&lt;/strong&gt;.
For a good measure, let&amp;rsquo;s release all those tasks by putting some values onto the channels with another loop &lt;code&gt;(each [_ c (ipairs channels)] (async.put c 42))&lt;/code&gt; (another 163 seconds to complete), and then re-run the &lt;code&gt;bench&lt;/code&gt; function, to check that it is fast again.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00029706954956055
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.8214874267578e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.7751617431641e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0599060058594e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6.1988830566406e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.8214874267578e-06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.5974044799805e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.4080276489258e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we&amp;rsquo;re back to being fast again.
Yay!..&lt;/p&gt;
&lt;p&gt;This is a major downside of the system that keeps track of all tasks - there&amp;rsquo;s no way of optimizing it because it has to check for all tasks every time - what if some tasks are no longer blocked and can advance?
We can&amp;rsquo;t even partition those tasks, because, as in the example above, the task is not related to timed events at all.
Because of that, I decided to re-implement the library from scratch, but I already &lt;a href=&#34;https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/&#34;&gt;blogged&lt;/a&gt; about it.&lt;/p&gt;
&lt;h3 id=&#34;fake-it-til-you-actually-need-it&#34;&gt;Fake it til you actually need it&lt;/h3&gt;
&lt;p&gt;In the new version of the library, I avoided the scheduler altogether.
Well, there is a scheduler still, but unless you&amp;rsquo;re using &lt;code&gt;timeout&lt;/code&gt; channels, you can live completely without it (for the most part, that is).
BTW, I shouldn&amp;rsquo;t call it a new version of the library, it is simply a different library, but the facilities are largely the same for both, so we can compare them.&lt;/p&gt;
&lt;p&gt;First things first, let&amp;rsquo;s test the code from the above with the new library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;import-macros &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;take!&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:socket&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bench&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that loops putting the values one by one, and tracks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; the time when it completed each put&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a thread that takes values, and measures the amount of time it took&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for value to be transferred.  Loops for more until the channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; is closed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gettime&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; waits til both threads are done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lock&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8.9883804321289e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4.6968460083008e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00019192695617676
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4.6014785766602e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00013494491577148
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.8835067749023e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.7990036010742e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2.0027160644531e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.8943710327148e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3.0994415283203e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The overall speed is more or less the same but now, let&amp;rsquo;s repeat the same trick, again creating &lt;code&gt;10000&lt;/code&gt; channels, and registering a task on each of them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; create 10000 channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; spawn 10000 tasks waiting on these channels&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not only this code executes almost immediately, taking about a second, but this amount of channels also don&amp;rsquo;t affect our &lt;code&gt;bench&lt;/code&gt; function at all:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (bench)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00028419494628906
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.2029571533203e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00049304962158203
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6.6041946411133e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00028800964355469
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5.1021575927734e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00026488304138184
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5.6982040405273e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0.00023293495178223
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7.9870223999023e-05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, what&amp;rsquo;s the trick?&lt;/p&gt;
&lt;p&gt;If we take a look at the internals of the library, there&amp;rsquo;s also a queue of dispatched tasks, called, well &lt;code&gt;dispatched-tasks&lt;/code&gt;.
We can load the library as a whole into the REPL and poke around:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 10000] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;ManyToManyChannel&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55fbd1d328d0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:takes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;reify&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55fbd2cbb690&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Handler&amp;gt;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, even though we&amp;rsquo;ve actually created &lt;code&gt;10000&lt;/code&gt; channels plus a 10000 of &lt;code&gt;go&lt;/code&gt; blocks, each of which is also a channel, and registered a pending take (&lt;code&gt;&amp;lt;!&lt;/code&gt;) on each one, no tasks were actually added to the &lt;code&gt;dispatched-tasks&lt;/code&gt; at all.
A task is only added to the scheduler when the channel is used!
In other words, once we put something onto a channel, that has a pending take, only then the task will be scheduled to execute:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt; 1) 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x55dcaf30ecb0&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means that the work done by the scheduler is limited to the amount of resources really used by the program at a given point in time.
So our partitioning problem is gone.
There&amp;rsquo;s still another problem though - we need to run the scheduler somehow.&lt;/p&gt;
&lt;p&gt;Now we can talk about hooks.&lt;/p&gt;
&lt;h2 id=&#34;hooks--the-wrong-way&#34;&gt;Hooks (the wrong way)&lt;/h2&gt;
&lt;p&gt;Initially, when implementing this system I realized, that while the scheduler actually isn&amp;rsquo;t necessary for plain channels at all, because you can always delay the execution of a pending operation until the channel is ready this won&amp;rsquo;t work if I add timeout channels.
And actually, before I introduced timers to the library, there wasn&amp;rsquo;t any &lt;code&gt;dispatched-tasks&lt;/code&gt; kind of thing at all, so the library was truly scheduler-less.
But after I ported the whole thing from ClojureScript, I had to add timeout channels to be fully compatible, thus the scheduling had to be introduced too.&lt;/p&gt;
&lt;p&gt;For a brief note, a &lt;code&gt;timeout&lt;/code&gt; function returns a channel that closes automatically after the specified period of time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 300))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; s&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0.3021879196167 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But how exactly it knows when to close?
While we can block our main thread with &lt;code&gt;&amp;lt;!!&lt;/code&gt; OP and inspect the timeout object for the time it needs to sleep, thus putting the main thread to sleep for that time it will also stop all other background tasks from happening.
And if the timeout is awaited asynchronously in a &lt;code&gt;go&lt;/code&gt; block, we can&amp;rsquo;t do even that.&lt;/p&gt;
&lt;p&gt;So, we do need a scheduler that will run regularly and will check for any timeouts that are ready to be released.
My initial thought was that I once again need some kind of &lt;code&gt;scheduler.run&lt;/code&gt; function that will need to be manually called by each function in the library, but this approach has other problems too.&lt;/p&gt;
&lt;p&gt;For example, what if the user will write a tight loop that will run for too long and we&amp;rsquo;ll miss the time we need to release a timeout?
Well, that isn&amp;rsquo;t &lt;em&gt;that&lt;/em&gt; big of a deal, but I&amp;rsquo;d like not to have a system that is this unreliable.
The user can even forget to call &lt;code&gt;scheduler.run&lt;/code&gt; in their loop, wondering why the timer doesn&amp;rsquo;t even count.
So I started searching for other approaches.&lt;/p&gt;
&lt;p&gt;The solution was to use &lt;code&gt;debug.sethook&lt;/code&gt; with some options, to run the hook regularly enough that it will not cause serious performance hit for the system as a whole, and will update timers with enough precision.
And that&amp;rsquo;s exactly what the ClojureScript version of the library &lt;a href=&#34;https://github.com/clojure/core.async/blob/9ebd84a29c943afd1d47baecbeb0200e619e1e00/src/main/clojure/cljs/core/async/impl/dispatch.cljs#L34-L37&#34; target=&#34;_blank&#34;&gt;does&lt;/a&gt;!
Except it uses the &lt;code&gt;goog.async&lt;/code&gt; thing, which I have no idea how it works, but the solution is simple and effective.
As far as I know, JavaScript has some facilities to register callbacks to be run after a certain amount of time, so maybe it&amp;rsquo;s something along the line there.&lt;/p&gt;
&lt;p&gt;So I decided to try this out and made a simple hook that runs every time we return from functions, and every &lt;em&gt;one thousand VM instructions&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ----8&amp;lt;---- piece of old code ahead -----8&amp;lt;-----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-advance-timeouts&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Close any timeout channels whose closing time is less than or equal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;to current time.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-remove&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-difftime&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-time&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-remove&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-timeouts&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-register-hook&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Run function `f` on each function return and every 1000 instructions.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Appends the hook to existing one, if found, unless the hook is `f`.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:r&lt;/span&gt; 1000)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;count&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-register-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-advance-timeouts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ----8&amp;lt;----&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it worked!
Satisfied with the result, and not paying any attention to the slowdown in the REPL, I moved on.
But the bitter taste of this code still followed me, as I knew that this isn&amp;rsquo;t a proper solution by any means.
This had many problems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first and obvious one is that the hook runs too frequently, but I didn&amp;rsquo;t think about it too hard because I had other stuff to port to the library.&lt;/li&gt;
&lt;li&gt;Second, and a bit less obvious, the hook runs &lt;em&gt;all the time&lt;/em&gt;, even if there are no timeout channels at all.
Unlike the ClojureScript solution, which schedules the hook once and only when needed, this one runs til the end of time.
Well, if there are no timeout channels it does nothing but the VM still stops to execute it each time the condition is met, which is bad.&lt;/li&gt;
&lt;li&gt;And third, I tried to keep the old hooks around, by using composition and thus made a foreign hook run possibly too often or even not often enough depending on the original settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Later, when I added the mentioned &lt;code&gt;dispatched-tasks&lt;/code&gt; table to the code, I started noticing the slowdown even more.
So I knew I need to do something.&lt;/p&gt;
&lt;h2 id=&#34;hooks--the-less-wrong-way&#34;&gt;Hooks (the less wrong way)&lt;/h2&gt;
&lt;p&gt;So, I&amp;rsquo;m pleased to say that all these problems were rectified recently.&lt;/p&gt;
&lt;p&gt;One morning, or a late night, I don&amp;rsquo;t really remember, I thought that it would be nice to actually measure how much time it takes for Lua to execute these 1000 instructions.
I then could adjust the parameter to only run the hook approximately 10ms after it was registered.
Ten milliseconds feels like a decent enough precision for timeout channels.
I mean no one in a sane mind will try to implement a &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Real-time_computing#Hard&#34; target=&#34;_blank&#34;&gt;hard real-time system&lt;/a&gt; with my library, or in Lua for that matter.
Even a firm one.&lt;/p&gt;
&lt;p&gt;Plus, to save up some performance and avoid keeping track of too many timers, I made an optimization to only create a new timer if the time passed since the previous one was created is greater than 10ms.
Thus, the timers at minimum are 10 milliseconds apart from each other.&lt;/p&gt;
&lt;p&gt;After a  bit of testing, it turned out that a million and a half instructions approximately take 10 ms to complete on my machine.
And while 1 million felt like a more appropriate amount to use for advancing timers, I knew that it would change on a per-machine basis, so I decided to tweak the system once more.&lt;/p&gt;
&lt;p&gt;Inspired by the ClojureScript approach, I thought that there was no need to run the hook &lt;em&gt;every&lt;/em&gt; &lt;code&gt;N&lt;/code&gt; instructions.
Instead, I can run it after &lt;code&gt;N&lt;/code&gt; instructions, and then disable it from within the hook itself.
Moreover, I can calculate how much time it took to execute this amount of instructions, and recalculate &lt;code&gt;N&lt;/code&gt; to set the hook to run 10ms in the future.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code behind that:&lt;/p&gt;
&lt;p&gt;And the main interface for hook scheduling.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-instr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-n&lt;/span&gt;) 1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_000_000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;schedule-hook&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os/clock&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook*&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cancel-hook&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sethook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main-thread&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?mask&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;?n&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  Hook cancellation. Returns the hook&#39;s settings for future analysis, and resets to the old hook if specified.
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-messages&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;took&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os/clock&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;register-time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cancel-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-messages&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-instr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:count&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;// &lt;/span&gt;0.01 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;took&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; 1 1024 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:until&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pcall&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeouts&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt;= &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;difftime&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeouts&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close!&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dispatched-tasks&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeouts&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;schedule-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-messages&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n-instr&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  The main body of the hook, that processes the messages. Re-registers itself if there&#39;s more work to be done. Calculates the amount of time it takes 1 instruction to complete, and uses it to reschedule itself 10ms after the execution.
&lt;/div&gt;
&lt;p&gt;In addition to that I opted out of combining several hooks into a single one.
This feels like a Lua problem - I don&amp;rsquo;t really understand why the VM only allows for a single hook to be registered.
Lua has five different events to hook up to, so why not allow registering five hooks?
And why isn&amp;rsquo;t it possible to register more than one hook for a single event type?
I mean, if there were many hooks registered, just run them in succession.&lt;/p&gt;
&lt;p&gt;I guess I can implement my own &lt;code&gt;sethook&lt;/code&gt; and replace the one that comes with the &lt;code&gt;debug&lt;/code&gt; library with my own version after someone loads my library.
Then register a handler that will keep track of all other hooks registered and run them accordingly.
Maybe I&amp;rsquo;ll try it.&lt;/p&gt;
&lt;p&gt;Two problems though - there&amp;rsquo;s no way of removing a &lt;em&gt;specific&lt;/em&gt; hook in stock Lua, and I will need to somehow determine what hook to call on &lt;code&gt;count&lt;/code&gt; events if more than one was registered.
Especially when each specifies a different amount of instructions.
I guess this is why there&amp;rsquo;s this kind of limitation in the stock &lt;code&gt;debug&lt;/code&gt; library, but I don&amp;rsquo;t think it&amp;rsquo;s impossible to do it in the VM itself with an ever-growing instruction counter.
Probably it&amp;rsquo;s just an optimization.&lt;/p&gt;
&lt;p&gt;In any case, the new system balances itself much better than before keeping 10ms intervals between tasks, and the slowdowns are gone.&lt;/p&gt;
&lt;p&gt;And while I was on it, I realized, that given the fact that I have both &lt;code&gt;scheduked-tasks&lt;/code&gt; and &lt;code&gt;timeouts&lt;/code&gt; storages, instead of checking for them in a hook, I can also do the check when I do a blocking operation.
This means that if the blocking operation only needs to wait for a timeout to close, it can actually sleep instead of doing a busy loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cpu-start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;CPU time: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;os.clock&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cpu-start&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; s&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; s&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;CPU&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0.169319 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Elapsed&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;1.0089449882507 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another realization came in that there is no point in doing any waiting if there are no active timeouts or tasks dispatched.
Because blocking the only thread means that no other thread can dispatch its task.
And a task can only be dispatched by another task, thus we can exit the waiting loop and throw an error without blocking the execution forever.
This doesn&amp;rsquo;t mean that we&amp;rsquo;re free from data races, far from it, but at least we can detect that the data will never arrive on a channel if we block.
In practice this shouldn&amp;rsquo;t happen too often.&lt;/p&gt;
&lt;p&gt;Probably, there are more clean ways of handling hooks than the one I&amp;rsquo;ve came up with, so feel free to suggest how to change the approach in the &lt;a href=&#34;https://gitlab.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;project&amp;rsquo;s repository&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: async.fnl enchancements&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 02 Aug 2023 09:10:00 +0300</pubDate>
    </item><item>
      <title>Game1 - Results</title>
      <link>https://andreyor.st/posts/2023-07-30-game1-results/</link>
      <guid>https://andreyor.st/posts/2023-07-30-game1-results/</guid>
      <description>&lt;p&gt;Well, this was fun!
A bit exhausting, actually.
The first of five months of the challenge has ended and here are the results:&lt;/p&gt;
&lt;iframe src=&#34;https://itch.io/embed-upload/8414750?color=3e3c57&#34;
        allowfullscreen=&#34;&#34;
        width=&#34;600&#34;
        height=&#34;320&#34;
        frameborder=&#34;0&#34;
        style=&#34;margin-left: auto; margin-right: auto; display: block;&#34;&gt;
  &lt;a href=&#34;https://andreyorst.itch.io/game1&#34;&gt;Play Game1 on itch.io&lt;/a&gt;
&lt;/iframe&gt;
&lt;p&gt;The game isn&amp;rsquo;t really complete, but I did my best to make it feel as complete as possible in the time constraints I had.
Technically, I have 1 day left, but given that I need to start working on the next game immediately I decided to give myself a day off.
It only features one level, and cuts out to the &amp;ldquo;you won&amp;rdquo; screen, but I still consider it a success.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the last bit of devlog for this particular game outlining some things I did since the last post in no particular order.&lt;/p&gt;
&lt;h2 id=&#34;graphic-overhaul&#34;&gt;Graphic overhaul&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve added parallax scrolling to the background, making the game happen inside a cave.
Well, at least, now the background is not that boring to look at, but it&amp;rsquo;s still plain.&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/background.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Then, I added a second layer and started experimenting with different colors:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/background2.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The problem with limited colors is that I can&amp;rsquo;t find a way of having foreground and background properly separated without using outlines on sprites, which I wanted to avoid for this game at least.
Thus, slimes are now blue instead of green.
But I like it more this way because it pops from the green ground a bit better.
And now that the background is also green it&amp;rsquo;s a lot more sensible.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve spent some time drawing foliage, like mushrooms, trees, grass, water, and so on.
None of this is animated though - time is once again against me.&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/foliage.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Also, added the menus, title screen, cover art, and some fade-in/out animations for smoother transitions:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/transitions.gif&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;enemy-ai&#34;&gt;Enemy AI&lt;/h2&gt;
&lt;p&gt;While I wanted to add more enemy types to the game I simply ran out of time, so the game only features basic slimes.
Their AI is extremely simple too - just roam forward until there&amp;rsquo;s no more ground, a wall, or another entity, then turns around.&lt;/p&gt;
&lt;p&gt;Still, I had some trouble implementing this at first, as I tried to use the &lt;code&gt;world:check&lt;/code&gt; method to try and move the slime forward and below to check if there&amp;rsquo;s ground to traverse on.
But this didn&amp;rsquo;t work for some reason, so I opted for advanced bump API &lt;code&gt;world:queryRect&lt;/code&gt; and queried the rectangle below the slime instead.
It worked nicely, and perhaps I&amp;rsquo;ll use this to make a more robust AI in future games.&lt;/p&gt;
&lt;p&gt;I was toying for a little bit with flying enemies, but it&amp;rsquo;s hard to make them work right with the environment.
I didn&amp;rsquo;t want something like Medusa heads from Castlevania games, but that&amp;rsquo;s exactly what I got during testing.&lt;/p&gt;
&lt;p&gt;I also finally added the death mechanic, as previously the game lacked it completely.
Death doesn&amp;rsquo;t take away your score, as the game turned out to be hard, and there are not enough coins in the only level to get 100 of them and earn an extra life.&lt;/p&gt;
&lt;h2 id=&#34;level-design&#34;&gt;Level design&lt;/h2&gt;
&lt;p&gt;Probably shouldn&amp;rsquo;t have left this to the last possible moment, but designing interesting levels turned out to be a lot harder than I thought initially.
I think I&amp;rsquo;ve managed to at least do a somewhat challenging one, but you&amp;rsquo;re the judge here.
Probably most enemies and traps are cheap.&lt;/p&gt;
&lt;p&gt;As I mentioned previously, I&amp;rsquo;ve used the map editor to construct the level:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/level.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s a shame though that &lt;a href=&#34;https://www.mapeditor.org/&#34; target=&#34;_blank&#34;&gt;Tiled&lt;/a&gt;, a tilemap editor, doesn&amp;rsquo;t support TIC&amp;rsquo;s maps.
Well, there&amp;rsquo;s a converter but it didn&amp;rsquo;t work for me.
Map editor in TIC isn&amp;rsquo;t bad, but it isn&amp;rsquo;t as good as something like Tiled.
For example, Tiled has randomization from a selected set of tiles when you paint with them, which makes things like ground feel less repetitive.
In TIC I had to do it by hand, and I may have forgotten to do it somewhere in the game, so excuse me if you&amp;rsquo;ll see something like that.&lt;/p&gt;
&lt;p&gt;I used the bottom of the map to draw menus, backgrounds, transitions, and so on, as can be seen here:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/map.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;My initial idea was to implement the first few levels like this, one below another, and then switch the memory bank, draw a new set of tiles, and make more levels.
But not only I ran out of time, I also ran out of ideas.
Maybe next time.&lt;/p&gt;
&lt;p&gt;Overall, I&amp;rsquo;d say making levels isn&amp;rsquo;t my least favorite thing so far but it&amp;rsquo;s close.
I&amp;rsquo;ve played in a fair bit of games with level editors and even published some online, but it never grew on me.
I guess I&amp;rsquo;m not a level designer at heart.&lt;/p&gt;
&lt;h2 id=&#34;music-and-sfx&#34;&gt;Music and SFX&lt;/h2&gt;
&lt;p&gt;This was probably the hardest part.
I can&amp;rsquo;t compose music and TIC&amp;rsquo;s tracker is alien to me. Sound design is a bit easier, but I don&amp;rsquo;t know a lot of tricks, so sounds in this game are far and few between.
Still was worth a shot.&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/coin-sound.png&#34;/&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;up-next&#34;&gt;Up next&lt;/h2&gt;
&lt;p&gt;The next game in the challenge is a roguelike.
This kind of game poses different problems, like pathfinding, more complex enemy AI in general, randomization of levels, items, etc.
I kinda feel exhausted right now but I&amp;rsquo;ll still try not to repeat the mistake I made and not procrastinate too much in the first weeks.
Though the next month is packed with various life-related events, much more than this one, so we&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;As for this game, here&amp;rsquo;s the cartridge if you want to play it yourself:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-30-game1-results/game1.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Though, because the original code requires a more recent version of Fennel than the one TIC provides, the code in the cart above was AOT compiled to Lua and isn&amp;rsquo;t very readable.
Also note that the last stable release of TIC still contains the &lt;a href=&#34;https://github.com/nesbox/TIC-80/issues/1904&#34; target=&#34;_blank&#34;&gt;#1904&lt;/a&gt; bug, which means that my game will run ~10 times slower than it should.
So you either need to play the game on the itch.io page, as it features a more recent version, build a standalone version yourself, or use an older release with the Lua version above.
You can read the original source code at the itch.io page linked above, or in the &lt;a href=&#34;https://gitlab.com/andreyorst/game1/-/blob/main/cart.fnl&#34; target=&#34;_blank&#34;&gt;game repository&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 - Results&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 30 Jul 2023 15:29:00 +0300</pubDate>
    </item><item>
      <title>Game1 W4/4 progress</title>
      <link>https://andreyor.st/posts/2023-07-26-game1-w44-progress/</link>
      <guid>https://andreyor.st/posts/2023-07-26-game1-w44-progress/</guid>
      <description>&lt;p&gt;This post is midway through the last week I have to work on the game in a platforming genre.
And it&amp;rsquo;s a bit of a shame because currently, I&amp;rsquo;m having a blast - now that the physics and camera are in place the game already feels like a playable thing.
So I decided to boost this feel and make some graphics so the world won&amp;rsquo;t look too boring to traverse.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t decided on what the world be like yet, but I&amp;rsquo;m running out of time, and also, I&amp;rsquo;m not that experienced in pixel art.
A few posts ago I wrote how I tried to do pixel art on the phone by using a stylus, and it worked pretty well for me.
So I took out the app again and started thinking about how would I use the colors that are still available to me.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve briefly considered changing the palette too.
The default TIC-80 palette is a bit weird for my taste, and it doesn&amp;rsquo;t include some colors that I&amp;rsquo;d like to have, e.g. brown.
I don&amp;rsquo;t know how, but every time I see some pixel art that uses this particular palette I swear it has brown, but upon closer inspection it&amp;rsquo;s an illusion caused by interplay with the other colors.
Unable to find a new palette that works, and also that doesn&amp;rsquo;t make every other sprite I drew up to this point use some weird colors, I gave up for now.
Maybe I&amp;rsquo;ll just look at what colors I don&amp;rsquo;t use at all or use too infrequently and replace them with the colors I need for my purposes.&lt;/p&gt;
&lt;p&gt;For now, I drew some grass on stone type of terrain (again, no brown for dirt!), and some construction site-type red bars:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/tiles.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Note, these are tiles, e.g. what goes on the map, but there are some things that are not part of the map, for example, the coin, or the slime enemy.
I&amp;rsquo;ll explain why they&amp;rsquo;re here shortly.&lt;/p&gt;
&lt;p&gt;And here are the sprites:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/sprites.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;As you can see, I&amp;rsquo;m storing these sprites mostly in rows, and tall sprites, like the player character look naturally in the editor.
Except for the ones in the third and fourth rows first half - these are horizontal sprites, but I still store them this way, because of how I do animations.
This reminds me that I haven&amp;rsquo;t explained anything regarding how my game works!
I guess I was too busy implementing it and didn&amp;rsquo;t have any spare time to write a proper post.&lt;/p&gt;
&lt;p&gt;So the animations are implemented in terms of sprites, obviously, but the way I set up them is a bit weird.
And I know, I definitively could save some space and re-use some sprites, because clearly there are doubles or even triples of the same sprite.
But it was easier this way, so I did it anyway.
I have this function, called &lt;code&gt;sprites&lt;/code&gt; that takes an id of the first sprite, the last sprite, and an optional &lt;code&gt;loop?&lt;/code&gt; parameter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:loop?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop?&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result of this function is a table, that simply holds a range of IDs for all the sprites in the animation.
Does the &lt;code&gt;n&lt;/code&gt; key hold the total count of sprites, and &lt;code&gt;loop?&lt;/code&gt;, well, we&amp;rsquo;ll get to it in a moment.&lt;/p&gt;
&lt;p&gt;The other component of animation is how I choose when to change the frame.
I&amp;rsquo;m sure there&amp;rsquo;s a different, and probably more robust way of doing this, but what I&amp;rsquo;ve settled on is this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-frame&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.last-draw-time&lt;/span&gt; 0))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; 60)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sprites&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m/floor&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; 60))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.last-draw-time&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites.n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites.loop?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:number&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clamp&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.frame&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;obj.last-draw-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, this function receives an object &lt;code&gt;obj&lt;/code&gt; and a delta time &lt;code&gt;dt&lt;/code&gt;.
The object stores its own draw time, and when the sum of &lt;code&gt;dt&lt;/code&gt; and this time is greater than &lt;code&gt;60&lt;/code&gt; I change the frame.
The &lt;code&gt;loop?&lt;/code&gt; field is used in a special way - when the next frame exceeds the total sprite count, we check if the animation should loop.
If the field is &lt;code&gt;true&lt;/code&gt; the animation loops from the first frame.
However, if the field is a number, we restart the animation from that number.
This way the animation can have a set of frames that act as preparation or transition, and then loop only the necessary part.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how I draw coins:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; 330 335 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:loop&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-collect-sprites&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sprites&lt;/span&gt; 346 351))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-coin&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sprites&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-sprites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-sprites&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt;) 511)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; -120 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt; -64 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) 0 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt; 2)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-collect-sprites&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coin-collect-sprites&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt;) 511)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;spr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-x&lt;/span&gt; -120 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cam-y&lt;/span&gt; -64 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;) 0 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frame&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collect-sprites.n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coins&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are some wonky numbers in here to adjust to the center of the screen and camera position in the world, but the code should be straightforward.
The &lt;code&gt;(self:sprites)&lt;/code&gt; call simply returns the object&amp;rsquo;s current set of sprites, which I change in other functions depending on the situation.
E.g. if the coin was collected, the object&amp;rsquo;s sprite is changed to the &lt;code&gt;coin-collect-sprites&lt;/code&gt; which doesn&amp;rsquo;t loop, and the last sprite of that animation is invisible.
The coin itself is deleted from the world once the last &lt;code&gt;frame&lt;/code&gt; of the animation was played out.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/coin-animation.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This is the basis for all animation in the game.
Each object has it&amp;rsquo;s &lt;code&gt;:draw&lt;/code&gt; method, and each such method calls to &lt;code&gt;next-frame&lt;/code&gt; to understand what to display next time.&lt;/p&gt;
&lt;p&gt;Interaction with entities is done similarly - each entity has an &lt;code&gt;:interact&lt;/code&gt; method that decides what to do when a collision is detected.
For example, for the slime enemy, the method accepts the &lt;code&gt;y&lt;/code&gt; normal of the collision, and if it is not negative 1, which means that the collision happened from the side or from below, the player is damaged.
Otherwise, the slime sprite set is replaced with the stomp animation, and the object is deleted from the world:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/slime.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;By the way, I haven&amp;rsquo;t talked about how I structure the world yet.
You may know, that TIC has an inbuilt map editor:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/map-editor.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is basically a level designer for me because I&amp;rsquo;ve implemented a small function that upon loading the cart walks through each tile on the map and populates the world based on it.
I still use &lt;code&gt;map&lt;/code&gt; for drawing the level, but before that, all entity tiles are removed from the map, like in the image above coins and slimes, and the player&amp;rsquo;s head, which acts as a spawn point.
This way I can simply put objects in the map editor, and re-run the game, getting an updated world, complete with collectibles, power-ups, enemies, etc.:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted class=&#34;pixelart&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-26-game1-w44-progress/level.webm&#34; type=&#34;video/webm&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Here I&amp;rsquo;m obviously testing things out, but the game feels complete enough to actually start designing some actual levels.
I&amp;rsquo;m running out of time though, so perhaps I&amp;rsquo;ll just make a single course to complete, and that&amp;rsquo;s it.
But it&amp;rsquo;s already more than I&amp;rsquo;ve anticipated at the beginning!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also started working on the menu, but there&amp;rsquo;s nothing to show yet.&lt;/p&gt;
&lt;p&gt;From now, I&amp;rsquo;ll probably stop doing any in-game stuff, and concentrate on the level itself and I also need some audio to play when the player collects coins, takes damage, jumps, and so on.
Maybe I&amp;rsquo;ll even include some music if I&amp;rsquo;ll manage to compose something not too annoying to listen to.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 W4/4 progress&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 26 Jul 2023 20:09:00 +0300</pubDate>
    </item><item>
      <title>Game1 W3/4 (again)</title>
      <link>https://andreyor.st/posts/2023-07-22-game1-w34-again/</link>
      <guid>https://andreyor.st/posts/2023-07-22-game1-w34-again/</guid>
      <description>&lt;p&gt;Who knew that writing a post about how I&amp;rsquo;ve procrastinated for two whole weeks instead of following my own challenge would be so motivating?
Immediately after I posted the previous post on Monday, I regained interest and started working on physics integration.
Well, making a platformer without experience turned out to be harder than I thought, though I got stuck on things that are not platformer specific.&lt;/p&gt;
&lt;p&gt;For the first half of the week, I&amp;rsquo;ve been trying to implement collision resolution myself.
This&amp;hellip; didn&amp;rsquo;t go well, as can be seen here:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-22-game1-w34-again/custom-collisions.gif&#34;
         alt=&#34;Figure 1: The green rectangles depict the area in which I check for possible collisions, and red rectangles mark tiles that collided with the player&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;The green rectangles depict the area in which I check for possible collisions, and red rectangles mark tiles that collided with the player&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve read some tutorials on &lt;a href=&#34;https://github.com/nesbox/TIC-80/wiki/tutorials&#34; target=&#34;_blank&#34;&gt;TIC&amp;rsquo;s wiki&lt;/a&gt;, mainly &lt;a href=&#34;https://medium.com/@btco_code/writing-a-platformer-for-the-tic-80-virtual-console-6fa737abe476&#34; target=&#34;_blank&#34;&gt;this&lt;/a&gt; one.
It mentions how to track collisions by checking nearby squarest cells on the map grid.
That was exactly my idea, but it didn&amp;rsquo;t work well, as was shown in the GIF above.&lt;/p&gt;
&lt;p&gt;I suspect the main reason for that is that the player object moves at irregular intervals because the distance is determined by velocity, and not constant as in the tutorial.
Thus, the object often overshoots or undershoots the wall and the floor, which led to the player stuck in walls, or going completely through them.
It reminded me of problems I had with my &lt;a href=&#34;https://andreyorst.itch.io/brick-game-with-a-twist&#34; target=&#34;_blank&#34;&gt;previous game&lt;/a&gt;, where the ball often got through the platform and bricks, so after failing to do physics again I decided to use a library.&lt;/p&gt;
&lt;p&gt;Using a library in a TIC game means that the library has to be included in the game cart because there&amp;rsquo;s no other way of shipping games for this platform - a cart is a self-contained program without external dependencies.
TIC&amp;rsquo;s carts also have limited capacity so the amount of code I can include is also limited.
Fortunately, there&amp;rsquo;s a small enough library called &lt;a href=&#34;https://github.com/kikito/bump.lua&#34; target=&#34;_blank&#34;&gt;bump.lua&lt;/a&gt; that does AABB collision detection, which is exactly what I need for this type of game.
TIC games are tile-based, so axis-aligned rectangles are exactly what I need to handle.
With some trickery, it is even possible to implement slopes by using special kinds of boxes that define a slope offset based on the X coordinate.&lt;/p&gt;
&lt;p&gt;There was a problem though.
&lt;code&gt;bump.lua&lt;/code&gt; is a Lua library, and while TIC supports Lua, I&amp;rsquo;m doing this game in Fennel.
Usually, it&amp;rsquo;s not a problem, because projects written in Fennel can use Lua libraries without any issues, and technically I could have used &lt;code&gt;bump.lua&lt;/code&gt; as a library from TIC-80 too.
But, as I mentioned, TIC carts must be self-contained, and thus can&amp;rsquo;t load an external library.
So I had to decide - either I port &lt;code&gt;bump.lua&lt;/code&gt; to Fennel, or compile my Fennel code to Lua and continue the development this way.
I also considered re-implementing a smaller subset of &lt;code&gt;bump.lua&lt;/code&gt; specifically for using it in TIC with map tiles, which would probably make the library smaller and easier to handle, but I decided that I want to actually see some results of my work at the end of this month.&lt;/p&gt;
&lt;p&gt;There was another compelling way of handling this situation though.
I could have used Fennel&amp;rsquo;s &lt;code&gt;-require-as-include&lt;/code&gt; compile flag to, well, include &lt;code&gt;bump.lua&lt;/code&gt; as an embedded dependency, and after the development is finished compile the cart to Lua right before shipping.
This would be the easiest way of doing things, as it would mean that I can do a completely normal development and use any libraries I want, but the downside is that the cart will be a hot mess of obfuscated Lua code, and I wanted the cart to actually contain something readable.
Maybe I&amp;rsquo;ll try this in the future, who knows?&lt;/p&gt;
&lt;p&gt;So, after some consideration of continuing in Lua and just copying &lt;code&gt;bump.fnl&lt;/code&gt; code into the cart, I decided to translate &lt;code&gt;bump.lua&lt;/code&gt; to Fennel.
As much as I like Lua, Fennel is more pleasant to work with.
It wasn&amp;rsquo;t that hard to do, given that there&amp;rsquo;s an &lt;a href=&#34;https://fennel-lang.org/see&#34; target=&#34;_blank&#34;&gt;excellent Lua-to-Fennel decompiler&lt;/a&gt;, that did most of the job.
It does generate weird code here and there, calling &lt;code&gt;set-forcibly!&lt;/code&gt; every now and then, and inserting &lt;code&gt;(lua &amp;quot;return &amp;quot;)&lt;/code&gt;  in places where Lua code had a sole &lt;code&gt;return&lt;/code&gt;, or doing things like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- original Lua code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sortByTiAndDistance&lt;/span&gt;(a,b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; a.ti == b.ti &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ir, ar, br = a.itemRect, a.otherRect, b.otherRect
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; ad = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, ar.x,ar.y,ar.w,ar.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; bd = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, br.x,br.y,br.w,br.h)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; ad &amp;lt; bd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; a.ti &amp;lt; b.ti
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Lua decompiler result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sort-by-ti-and-distance&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;values &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.itemRect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.otherRect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.otherRect&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.h&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;___antifnl_rtn_1___&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold&#34;&gt;lua &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;return ___antifnl_rtn_1___&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; cleaned version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sort-by-ti-and-distance&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.itemRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.otherRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.otherRect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ar.h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rect-get-square-distance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ir.h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;br.h&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ad&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bd&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a.ti&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b.ti&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  e.g. here, the decompiler transformed a single-branch &lt;code&gt;if&lt;/code&gt; into &lt;code&gt;when&lt;/code&gt; and generated an explicit return, but a smarter decompiler could transform this into two branched &lt;code&gt;if&lt;/code&gt; without any early returns. Conceptually these two variants are the same, except one is more like the guard-return style and another is more like actual lisp-style.
&lt;/div&gt;
&lt;p&gt;So I took some extra time to clean all &lt;code&gt;set-forcibly!&lt;/code&gt; calls, restored the original comments which were lost during translation, and removed all instances of explicit early returns, by converting the code to use branches instead.
After compiling the library back to Lua, I tested it with some demos listed in the library&amp;rsquo;s readme and it worked fine, so I hope I didn&amp;rsquo;t introduce any new bugs during the cleanup state.
The next thing was to integrate it into the game.&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t that hard to do, as I just copied the whole library code into the cart, but I was worried if it will be able to handle &lt;em&gt;lots&lt;/em&gt; of squares.
My idea was to iterate over every map cell, check if it is solid or not, and if so add it to the world.
Thus, each non-empty tile on the map exists in the world and acts as a collideable object.
As a result, I can use the map editor basically as a level editor, as adding a tile basically is like adding a world object.&lt;/p&gt;
&lt;p&gt;The resulting performance seems to be fine on my PC, though I&amp;rsquo;m unsure about the browser which I&amp;rsquo;ll target to make the game playable on my itch.io web page.
I&amp;rsquo;m still exploring the idea of using special tile flags to make rooms longer than they seem on the map, as described in the platformer tutorial that I&amp;rsquo;ve mentioned.
But this probably requires special handling when it comes to integrating it with the bump library.
For now, the result (with some debug info) looks like this:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-22-game1-w34-again/bump.gif&#34;
         alt=&#34;Figure 2: bump.lua in TIC-80 with some debug visualisations of collisions&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;bump.lua in TIC-80 with some debug visualisations of collisions&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The next thing to do was the camera.
Now, since each object in the world has the same coordinate as the map, the only thing I need to do is implement the translation of world coordinates to screen coordinates based on player position with some slight interpolation.
Fortunately enough, there&amp;rsquo;s a handy &lt;a href=&#34;https://github.com/nesbox/TIC-80/wiki/Camera-tutorial&#34; target=&#34;_blank&#34;&gt;tutorial&lt;/a&gt; on camera movement, and while I&amp;rsquo;d like to try and implement this myself, I decided to rely on external source of wisdom.&lt;/p&gt;
&lt;p&gt;Unfortunately, for some weird reason, the camera described in this tutorial worked differently for me.
For some reason, the player sprite was drawn in the top left corner of the screen, and the camera was also positioned there.
I mean, it moves correctly but is unplayable in this state.
After I&amp;rsquo;ve &lt;em&gt;experimented&lt;/em&gt; with some random numbers I&amp;rsquo;ve managed to get it to work:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-22-game1-w34-again/camera.gif&#34;
         alt=&#34;Figure 3: The camera moves with a slight delay to add a bit more dynamic feel, but I didn&amp;amp;rsquo;t go for a more proper camera implementation that tries to show more in the direction of movement yet. Also, what&amp;amp;rsquo;s up with these GIFs generated by TIC, their size is around 10MB each, so I had to heavily compress them myself, yet they look entirely the same afterwards.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;The camera moves with a slight delay to add a bit more dynamic feel, but I didn&amp;rsquo;t go for a more proper camera implementation that tries to show more in the direction of movement yet. Also, what&amp;rsquo;s up with these GIFs generated by TIC, their size is around 10MB each, so I had to heavily compress them myself, yet they look entirely the same afterwards.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;With that in place, now I need to design some levels and add more graphics, and sounds.
As well, as implement actual environment interactions, such as roaming and collideable enemies, stationary hazards like spikes, health, score, and respawn systems, and maybe some other intractable objects, like coins to collect.
Not sure what I&amp;rsquo;ll do first, probably the latter, as it will teach me how to add collideable items to the world that should not be treated as platforms.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 W3/4 (again)&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 22 Jul 2023 21:03:00 +0300</pubDate>
    </item><item>
      <title>Game1 W3/4</title>
      <link>https://andreyor.st/posts/2023-07-17-game1-w34/</link>
      <guid>https://andreyor.st/posts/2023-07-17-game1-w34/</guid>
      <description>&lt;p&gt;Long story short, no progress so far.
I&amp;rsquo;m starting to think that the way I&amp;rsquo;ve set this challenge up actually mostly demotivates me to continue rather than encourages me to press forward.
To say that I&amp;rsquo;ve been working on Game1 will be both a lie to myself and to you.
Well, I did, but in a tinkerer&amp;rsquo;s fashion - rewriting one piece of code til I&amp;rsquo;m satisfied (except I never am).&lt;/p&gt;
&lt;p&gt;So far I&amp;rsquo;ve managed to put sprites into the TIC-80 engine and created a simple controller, that actually doesn&amp;rsquo;t work how I expected it to, and that&amp;rsquo;s it:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-07-17-game1-w34/player-controller.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Mostly because for the past two weeks I was either distracted by work or by working on a new Emacs window manager described in the last post (that, probably, no one needs, even me).&lt;/p&gt;
&lt;p&gt;I have two weeks left (including this one), and I don&amp;rsquo;t think I&amp;rsquo;ll be able to finish this one in time, at least in its full shape.
Maybe I&amp;rsquo;ll settle on a simpler thing, like a demo in which I just explore how to write a platformer, it&amp;rsquo;ll still be a good start.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1 W3/4&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 17 Jul 2023 23:07:00 +0300</pubDate>
    </item><item>
      <title>Emacs GUI library</title>
      <link>https://andreyor.st/posts/2023-07-11-emacs-gui-library/</link>
      <guid>https://andreyor.st/posts/2023-07-11-emacs-gui-library/</guid>
      <description>&lt;p&gt;Lately, my Magit buffer broke once again because of something weird going on with major mode, and I couldn&amp;rsquo;t stash or commit hunks unless the point was at the beginning of the line.
That once again reminded me that Emacs UI is not really a UI, all of it is mere text with a bunch of properties slapped on top.
It&amp;rsquo;s easy to forget about it, and use such things like Treemacs, Customize, heck, even Org Mode, thinking that you&amp;rsquo;re interacting with UI elements (file nodes in Treemacs, text-boxes in Customize, Org Modes sub-trees and drawers).
However, it is an illusion, though neatly crafted.
It&amp;rsquo;s still text.&lt;/p&gt;
&lt;p&gt;Well, what&amp;rsquo;s bad about it you might ask?
We love to manipulate text, Emacs even makes it actually comfortable to do, with a lot of functions dedicated to it.
And buffers are also a very fast way to manipulate even moderate amounts of text.
But ask yourself, do you really want to do the same kind of thing in a different UI system, outside of Emacs?
Maybe if it came with the same amount of useful functions?
Well, maybe you&amp;rsquo;d want to, but I sure don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve made my own custom UI elements in Kakoune, making a file tree, and tag list plugins.
That was before I actually started using Emacs as my main environment, and Kakoune text properties are much less sophisticated than ones of Emacs, but&amp;hellip;
It&amp;rsquo;s the same thing, really.&lt;/p&gt;
&lt;p&gt;You programmatically spit some text into the buffer, then you parse it, find elements, walk on them, change them, and so on.
Yes, text properties, markers, overlays, all of it makes it more robust in Emacs, but even though, things still break.
Because Emacs still tries to interpret stiff in your buffer as text.&lt;/p&gt;
&lt;p&gt;Because that&amp;rsquo;s what it does, it expects text!
If you call &lt;code&gt;forward-sexp&lt;/code&gt; on some Magit UI element it will try to do the right thing, even if there&amp;rsquo;s no right thing - there are no sexps in the Magit buffer.
Well, maybe there are if you&amp;rsquo;re viewing diffs of your lisp code, and then yeah, the benefit of everything being text you can move on becomes obvious.
Except when we&amp;rsquo;re talking about UI it&amp;rsquo;s not working more of the times than it is useful in an occasional context of that UI element.&lt;/p&gt;
&lt;p&gt;I think you probably get where I&amp;rsquo;m going with this.
And you probably don&amp;rsquo;t like it, but bear with me.
And it&amp;rsquo;s an angry bear, so don&amp;rsquo;t threaten me more than he does, please.&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;m trying to say is that Emacs, as a GUI application isn&amp;rsquo;t something that I&amp;rsquo;d be advertising to other people.
You can make Emacs look beautiful, no doubt about that, &lt;a href=&#34;https://github.com/rougier/nano-emacs&#34; target=&#34;_blank&#34;&gt;Nano&lt;/a&gt; Emacs, &lt;a href=&#34;https://github.com/doomemacs/doomemacs&#34; target=&#34;_blank&#34;&gt;DOOM&lt;/a&gt;, and others try very hard to make Emacs visually appealing.
But it&amp;rsquo;s all too janky IMO.
Nano Emacs looks great on the pictures, but resize a window and the illusion of a coherent interface breaks fast.
So let&amp;rsquo;s look at different systems for inspiration:&lt;/p&gt;
&lt;h2 id=&#34;smalltalk&#34;&gt;Smalltalk&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve already mentioned Smalltalk in the past regarding comparison with Emacs in the GUI field.
And I think it is a fair thing to do - both are dynamic systems that you can program with their respective language.
Except, one is GUI oriented pretty much from the start, and the other one is Emacs.&lt;/p&gt;
&lt;p&gt;Look at how Smalltalk looks when you fire up Pharo:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/pharo.gif&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It&amp;rsquo;s a GUI &lt;em&gt;system&lt;/em&gt;.
Complete with windows, containing text editors, browsers, context-aware menus, and so on.
Maybe it doesn&amp;rsquo;t look as pretty as your preferred GUI toolkit, but it&amp;rsquo;s not the main point.&lt;/p&gt;
&lt;p&gt;Although, here&amp;rsquo;s how Smalltalk looks when you fire up GToolkit, which is written in Pharo:&lt;/p&gt;
&lt;div class=&#34;horizontal-gallery&#34;&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/gtoolkit-1.png&#34;
         alt=&#34;Figure 1: Visualizing the current knowledge base through a Pharo snippet. Clicking on nodes opens the page to the right.&#34; width=&#34;640px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Visualizing the current knowledge base through a Pharo snippet. Clicking on nodes opens the page to the right.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/gtoolkit-2.png&#34;
         alt=&#34;Figure 2: A page with a JavaScript snippet that is combined with a Pharo snippet to produce a visualization of dependencies defined in a Yarn file.&#34; width=&#34;640px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;A page with a JavaScript snippet that is combined with a Pharo snippet to produce a visualization of dependencies defined in a Yarn file.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/gtoolkit-3.png&#34;
         alt=&#34;Figure 3: Explaining a domain object through examples and custom views.&#34; width=&#34;640px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Explaining a domain object through examples and custom views.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;There are much more pictures on the &lt;a href=&#34;https://gtoolkit.com/&#34; target=&#34;_blank&#34;&gt;official web page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The point of it is that you can build your own tools for your tasks in this toolkit, as shown in the pictures.
They call it building an inspector, and GToolkit comes with a lot of inspectors for various kinds of data.&lt;/p&gt;
&lt;p&gt;This is my favorite system so far, and it gets worse from here but I feel that we need to talk about other examples still.&lt;/p&gt;
&lt;h2 id=&#34;clojure&#34;&gt;&lt;del&gt;Java&lt;/del&gt; Clojure&lt;/h2&gt;
&lt;p&gt;Why not?
Clojure is another dynamic system, that you can change at runtime.
While Java isn&amp;rsquo;t what comes to mind when speaking about beautiful and functional GUI, making GUI apps in Clojure is far more fun than it is in Java.
Because again, you can update your UI elements on the fly.&lt;/p&gt;
&lt;p&gt;There are some examples of apps where the UI is done in Clojure, one example is the game engine called &lt;a href=&#34;https://defold.com/product/&#34; target=&#34;_blank&#34;&gt;Defold&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/defold.png&#34;
         alt=&#34;Figure 4: I couldn&amp;amp;rsquo;t find a non-skewed image on the official page.&#34; width=&#34;640px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;I couldn&amp;rsquo;t find a non-skewed image on the official page.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;As far as I understand, its Editor is made in Clojure, and UI is handled via the JavaFX toolkit.&lt;/p&gt;
&lt;p&gt;Intellij Idea is many another example of a decent-looking GUI in Java, although your opinion may vary.&lt;/p&gt;
&lt;p&gt;Still, JVM isn&amp;rsquo;t the greatest at UI, and somehow another language with a J in the name managed to do somewhat better.&lt;/p&gt;
&lt;h2 id=&#34;web&#34;&gt;Web&lt;/h2&gt;
&lt;p&gt;Lastly, the web is another way of building user interfaces, one that is quite popular today.
Because the web works the same across a majority of operating systems, as browsers are ported to them with a lot of care.
Browsers are also extremely capable of rendering all kinds of file formats, doing interactive stuff, and JavaScript frameworks are aimed at providing facilities for building UI that is highly responsive and interactive.&lt;/p&gt;
&lt;p&gt;The web is however associated with slow, often unresponsive UI, a lot of wasted screen space, and unnecessary high CPU and memory usage.
Mostly due to Electron packing lots of stuff.
I think Electron wasn&amp;rsquo;t a bad idea, the execution was just poor.
There are other projects that provide similar facilities like &lt;a href=&#34;https://ultralig.ht/&#34; target=&#34;_blank&#34;&gt;Ultralight&lt;/a&gt;, but I didn&amp;rsquo;t investigate further.
I&amp;rsquo;m OK with the idea of building UI on web technologies, as long as we&amp;rsquo;re making a robust system that works across multiple devices and actually benefits from using the browser.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also this project, which I find cool because it looks similar to GToolkit: &lt;a href=&#34;https://natto.dev/example/0a7aeb805e76412989946c5f270f84e5&#34; target=&#34;_blank&#34;&gt;natto.dev&lt;/a&gt;.
Basically, you get an infinite canvas, on which you can place text editing widgets, video widgets, and other stuff.
Keep this thing in mind, I find the idea of such UI interesting, and probably it will be explored more in the future.&lt;/p&gt;
&lt;p&gt;But, let&amp;rsquo;s get back to Emacs, and I&amp;rsquo;ll try to explain why I was bragging about all these other systems.&lt;/p&gt;
&lt;h2 id=&#34;emacs&#34;&gt;Emacs&lt;/h2&gt;
&lt;p&gt;Emacs has a windowing system.
Basically like a tiling window manager - you have a frame, you can divide it into windows, you can spawn other frames, you can divide them, and so on.
But, these windows can only display basic text, among some graphical elements, like SVG graphics, or bitmaps.
Needless to say, when compared to any of the systems I&amp;rsquo;ve talked about before the GUI capabilities of Emacs are quite limited.&lt;/p&gt;
&lt;p&gt;Basically, Emacs is a glorified terminal, with ability to draw different font sizes and decent image support.
Don&amp;rsquo;t make such a face, you know it&amp;rsquo;s not far from the truth.
Again, this may be a bit harsh, but I believe we need to admit things in order to move forward.&lt;/p&gt;
&lt;p&gt;Speaking of terminals, Emacs can actually run in a terminal!
You can start it with &lt;code&gt;emacs -nw&lt;/code&gt; and it will happily transform your terminal into Emacs.
I mean, you no longer have a terminal, it just acts as a rendering engine for Emacs.
So you basically get the same thing as GUI Emacs but worse, because now your terminal is responsible for rendering fonts, and you no longer have any image support.
Well, there are terminals that support images, but come on.&lt;/p&gt;
&lt;p&gt;And I think terminal support is one of the things that holds Emacs back.
Think about it - why do you even need a terminal if you&amp;rsquo;re already using Emacs?&lt;/p&gt;
&lt;p&gt;The common misconception is that you need a terminal version of Emacs to run it on headless environments, like servers, clouds, etc.
You don&amp;rsquo;t.
I work with remote servers constantly each day and I never open Emacs on the remote when I&amp;rsquo;m editing files there, I don&amp;rsquo;t even open a terminal for the SSH.
Here are some basic workflows involving remote servers or just terminal tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need to ssh somewhere to edit files or run some commands?
&lt;ul&gt;
&lt;li&gt;TRAMP got you covered.
&lt;ul&gt;
&lt;li&gt;You can even run &lt;code&gt;async-shell-command&lt;/code&gt; in a TRAMP buffer and it will be run on the remote.&lt;/li&gt;
&lt;li&gt;You even get to retain the entirety of your config without copying it onto the servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Need to run some commands in general?
&lt;ul&gt;
&lt;li&gt;Again, You can call &lt;code&gt;async-shell-command&lt;/code&gt;, it even will handle your input and password prompts in case there&amp;rsquo;s one;&lt;/li&gt;
&lt;li&gt;Or you can run &lt;code&gt;compile&lt;/code&gt;, which doesn&amp;rsquo;t handle prompts but still is much more interactive than the raw terminal output.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Want to run some complex commands with editing convenience, or maybe even some TUIs?
&lt;ul&gt;
&lt;li&gt;You can run &lt;code&gt;eshell&lt;/code&gt;, and go nuts on scripting in Emacs Lisp and calling sh scripts from the Emacs shell;&lt;/li&gt;
&lt;li&gt;Or you can run a proper terminal emulator from within Emacs:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/akermu/emacs-libvterm&#34; target=&#34;_blank&#34;&gt;Vterm&lt;/a&gt; - a terminal based on libvterm C library;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://codeberg.org/akib/emacs-eat&#34; target=&#34;_blank&#34;&gt;EAT&lt;/a&gt; - a terminal emulator that can run in a region, in a buffer, and in Eshell, written in Emacs Lisp;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ansi-term&lt;/code&gt;, &lt;code&gt;term&lt;/code&gt; - inbuilt terminal emulators in Emacs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don&amp;rsquo;t know how many times I got into a situation, where there&amp;rsquo;s a PDF documentation in one buffer, TRAMP in another, and I&amp;rsquo;m editing a remote file while referring to that documentation and staying within the comfort of Emacs.
So no, with Emacs terminal itself isn&amp;rsquo;t needed in maybe 90% of situations, and terminal Emacs is just out of the question.&lt;/p&gt;
&lt;p&gt;But hey, I too previously was a terminal enjoyer before Emacs, and it was too hard to even imagine how to even approach work without a terminal.
As I&amp;rsquo;ve mentioned, I was using Kakoune, and prior to that, I was a Vim user.
Now, with Emacs, I rarely open the terminal at all.
There&amp;rsquo;s simply no need to, as there are more comfortable ways of interacting with the shell.
And damn, even things like VSCode, which isn&amp;rsquo;t a terminal app at all, still manage to run as a server in a headless/remote/container context and provide you with all of its GUI features by acting as a client.
So yeah, ditch the terminal version of Emacs, you&amp;rsquo;re ain&amp;rsquo;t gonna miss it.&lt;/p&gt;
&lt;p&gt;Except, don&amp;rsquo;t.
Use what you like, the solution I&amp;rsquo;m going to propose doesn&amp;rsquo;t require anything to be ditched at all.
But before that, let&amp;rsquo;s talk XWidgets&lt;/p&gt;
&lt;h3 id=&#34;xwidgets&#34;&gt;XWidgets&lt;/h3&gt;
&lt;p&gt;When I was talking about the web, I&amp;rsquo;m sure some of you thought about XWidgets and Webkit support in Emacs.
Like, here, I&amp;rsquo;m running the already mentioned natto.dev inside my Emacs right now:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/emacs-1.png&#34; width=&#34;580px&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;So what gives?
And at work, I occasionally use Portal to navigate through nested data structures while debugging Clojure code:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/emacs-2.png&#34;
         alt=&#34;Figure 5: (the code isn&amp;amp;rsquo;t from work, just a hobby project)&#34; width=&#34;640px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;(the code isn&amp;rsquo;t from work, just a hobby project)&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Again, what gives?
This looks like we can have interactive GUIs in Emacs, much like in GToolkit and Pharo.
However, there&amp;rsquo;s a catch.
There&amp;rsquo;s always a catch, and in the case of Emacs, it&amp;rsquo;s that the XWidget UIs are &lt;em&gt;foreign&lt;/em&gt; to Emacs.&lt;/p&gt;
&lt;p&gt;Here, foreign means that inside that &lt;code&gt;*xwidget-webkit: portal...*&lt;/code&gt; buffer nothing you expect to work will actually work.
Remember how I mentioned that in Magit if you call &lt;code&gt;forward-sexp&lt;/code&gt; it will try to do the right thing?
Well, here it can&amp;rsquo;t do anything, because this isn&amp;rsquo;t a buffer really.
It is an embedded widget that only looks like a buffer in the Emacs window, but it&amp;rsquo;s not.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s &lt;em&gt;no point&lt;/em&gt; in calling &lt;code&gt;forward-sexp&lt;/code&gt; because there&amp;rsquo;s literally no point in such a buffer.
You can&amp;rsquo;t use &lt;a href=&#34;https://github.com/abo-abo/avy&#34; target=&#34;_blank&#34;&gt;Avy&lt;/a&gt; to jump to an element in such a buffer because there are no textual elements that Avy can look at.&lt;/p&gt;
&lt;p&gt;Because of it, it is basically the same as if you&amp;rsquo;ve opened a separate web browser side by side with Emacs and used it to browse the web, or run Portal, and it would probably even work better.
Unfortunately, we can&amp;rsquo;t embed something like Webkit into Emacs and hope that it will solve our UI problems.
Or can we?&lt;/p&gt;
&lt;h2 id=&#34;emacs-gui-toolkit&#34;&gt;Emacs GUI Toolkit&lt;/h2&gt;
&lt;p&gt;So here&amp;rsquo;s my idea.
I&amp;rsquo;m pretty sure it&amp;rsquo;s not new, but that&amp;rsquo;s not the point of this blog - it is merely a container for my thoughts, original or not.&lt;/p&gt;
&lt;p&gt;What if, instead of embedding Webkit into Emacs, we turn this around?
Hear me out.&lt;/p&gt;
&lt;p&gt;When I was talking about opening a browser side by side with Emacs two seconds ago, I should have mentioned that window managers, or WMs for short, are quite good at placing windows.
If you&amp;rsquo;re using some kind of a tiling manager, you know what I mean - you can leave window management to your window manager.
Kakoune, for instance, does exactly that - instead of creating its own windowing system, like Vim or Emacs, it leaves it out for things like TMUX or i3 to solve.
This, of course, has some problems too, but works well enough in general.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m not saying that we should ditch windowing from Emacs and leave it to the WM, far from it.
I would rather ditch frames from Emacs if you ask me, but that&amp;rsquo;s another topic.&lt;/p&gt;
&lt;p&gt;Look at this as if Emacs was embedded into your window manager, which is basically how it works.
You start your WM of choice&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, you launch Emacs, and as long as the Emacs window is focused, you live in Emacs.
All of your shortcuts work, and all of your navigation habits are there.&lt;/p&gt;
&lt;p&gt;So what if we expand on this idea?
Instead of embedding Webkit, let&amp;rsquo;s embed Emacs in its current state as a UI widget.&lt;/p&gt;
&lt;h3 id=&#34;the-widget-library&#34;&gt;The Widget Library&lt;/h3&gt;
&lt;p&gt;What I&amp;rsquo;m thinking is, let&amp;rsquo;s take, say SDL2 (or maybe something like &lt;a href=&#34;https://github.com/ocornut/imgui&#34; target=&#34;_blank&#34;&gt;ImGui&lt;/a&gt;), and create a library of widgets for Emacs.
We&amp;rsquo;ll then integrate Emacs into it as the runtime system behind it, much like in the case of Smalltalk, JavaFX+Clojure, and Web+JS, and provide a set of functions to navigate through widgets in a meaningful way.
The widgets would include basic stuff, like buttons, text boxes, buffers, drawers, menus&amp;hellip; wait, buffers?&lt;/p&gt;
&lt;p&gt;Yes, why ditch something that works well?
Like when you focus Emacs in your WM and it just works, when the buffer widget is in focus it will just work too!
We can keep the redisplay code, it will just need to learn how to render into such widgets, which I&amp;rsquo;m sure is possible, as there&amp;rsquo;s a very similar feature in Emacs already, called child-frames.&lt;/p&gt;
&lt;p&gt;With enough widgets, one will be able to build GUI, much like in GToolkit, but with Emacs Lisp, and we&amp;rsquo;ll still have all the legacy textual interface working, e.g. things like Magit don&amp;rsquo;t have to throw everything out of the window and adapt - they can continue to work.
We just need to be sure to provide enough extensibility, and a way to implement custom widgets, much like Emacs allows right now with its text properties, overlays, and such.
Then new plugins for the GUI toolkit will arrive, making Emacs even more extensible than before.&lt;/p&gt;
&lt;p&gt;Now, imagine, you open Emacs and it creates a window that is basically like a desktop of your operating system.
You open a window, and it&amp;rsquo;s a real window, floating on that desktop.
Don&amp;rsquo;t like it?
Just maximize it, the window widget will work similarly to how windows are created in Emacs right now.
Except it doesn&amp;rsquo;t have to be a window displaying a buffer and nothing else - it can display other widgets, some of which are buffers.&lt;/p&gt;
&lt;p&gt;Frames become virtual desktops, which they really are, it&amp;rsquo;s just that they&amp;rsquo;re represented as WM windows because Emacs didn&amp;rsquo;t include ways of switching them virtually (it did in the terminal mode actually).
You can still open a separate &amp;ldquo;frame&amp;rdquo; with a given virtual desktop, so again, everything would work as you&amp;rsquo;d expect.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve made a quick prototype that implements this.
Here&amp;rsquo;s a live demo:&lt;/p&gt;
&lt;p&gt;&lt;video controls autoplay loop muted width=&#34;640px&#34;&gt;&lt;source src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/infinite.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;And here&amp;rsquo;s Emacs running natto.dev and GToolkit pages in these child frames:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-07-11-emacs-gui-library/infinite.png&#34;
         alt=&#34;Figure 6: And there are some more windows below the screen that I can pan to&#34; width=&#34;640px&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;And there are some more windows below the screen that I can pan to&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;With this mode, I can create child frames, that act as small windows, and pan these around much like the natto.dev app I keep referring to.
Note that when the window tries to split itself, instead it creates a new window near it, and tries to keep windows from overlapping by finding empty space nearby.
Basically, this is almost like a different kind of window manager.&lt;/p&gt;
&lt;p&gt;Though this thing doesn&amp;rsquo;t work as well as you&amp;rsquo;d imagine, if you want to try it, you can get it &lt;a href=&#34;https://gitlab.com/andreyorst/infinite.el&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;the-future-of-emacs&#34;&gt;The future of Emacs&lt;/h2&gt;
&lt;p&gt;&amp;hellip;probably isn&amp;rsquo;t what I&amp;rsquo;m describing here.
I don&amp;rsquo;t know.
I&amp;rsquo;m just fantasizing, but the image of such a system I see behind my eyelids is great.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;depend&lt;/em&gt; on Emacs, it is my main tool for the job, this blog, my other hobbies, and other activities, so I want this system to evolve.
This is just a route I think it could take.
Again, maybe nothing of this makes any sense to you, but I encourage you to try out at least the GToolkit, I think it is the most interesting things I saw in the last years.
Pharo can be a bit less exciting but it laid the foundation for GT, and I think that&amp;rsquo;s says something.
If it wasn&amp;rsquo;t for Clojure, and maybe this blog which I do in Org-mode, and if I never used Emacs I would probably try GToolkit at some point, and maybe it would become my main tool, and I would probably look at Emacs as an inferior system.
Well, at least when it comes to GUI capabilities.
But I still love Emacs as it is, it fulfills my needs, and I can make it do what I want it to do, which is the main point.&lt;/p&gt;
&lt;p&gt;This post was mostly a collection of random thoughts, hence the category, but I genuinely think that if a system like this can be created in Smalltalk or in the current state of the web, it is definitively possible in Emacs, there&amp;rsquo;s just not that much of an interest in it.
Well, actually there is, as I&amp;rsquo;ve mentioned, people trying to make emacs more beautiful and appealing, but I think we should not forget about utility too, and thus if someone is to develop a GUI toolkit for Emacs they need to put a lot of thought into it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What widgets to include;&lt;/li&gt;
&lt;li&gt;How do you move from widget to widget in an efficient way;&lt;/li&gt;
&lt;li&gt;What is best done with a mouse, and what should not be done with it;&lt;/li&gt;
&lt;li&gt;What level of interactivity from Emacs Lisp we should get;&lt;/li&gt;
&lt;li&gt;Other questions like this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So yeah, it will take a lot of planning, prototyping, maybe some competing systems to progress on this - let&amp;rsquo;s see where Emacs will go in the upcoming 30 years.
Maybe another XEmacs will happen, or it will be forced to evolve by something like &lt;a href=&#34;https://project-mage.org/elevator&#34; target=&#34;_blank&#34;&gt;Project Mage&lt;/a&gt; or &lt;a href=&#34;https://nyxt.atlas.engineer/&#34; target=&#34;_blank&#34;&gt;Nyxt&lt;/a&gt;, or even another system, that would embrace GToolkit&amp;rsquo;s modal-less interface and infinite canvas.
The advent of virtual and/or augmented reality makes an interesting infinite-canvas type of interface candidate in my opinion, so maybe we&amp;rsquo;ll stop seeing flat screens in the future, who knows?&lt;/p&gt;
&lt;p&gt;Anyway, let me know what you think.
If you have any thoughts you like to share, you can find my contacts on the &lt;a href=&#34;https://andreyor.st/about&#34;&gt;About&lt;/a&gt; page.
Hope it was an interesting read!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I know that Emacs can be your WM of choice, no need to tell me that.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Emacs GUI library&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 11 Jul 2023 01:01:00 +0300</pubDate>
    </item><item>
      <title>Game1</title>
      <link>https://andreyor.st/posts/2023-06-30-game1/</link>
      <guid>https://andreyor.st/posts/2023-06-30-game1/</guid>
      <description>&lt;p&gt;As I stated a month ago, I&amp;rsquo;m going to force myself into game development with a &lt;em&gt;personal game dev marathon&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/em&gt; that will span over the next five months.
Technically, nothing prevents me from jumping off at any point, so I do want this to go as smoothly as possible, so I won&amp;rsquo;t burn out until I get out at least two games.
Well, we&amp;rsquo;ll see, of course - life often has its own plans for me, so&amp;hellip; yeah.&lt;/p&gt;
&lt;p&gt;The first game on my list is a platformer, which I wanted to be as simple as possible, e.g. basically run and jump.
I have no prior experience in making platformers, so this will be an exciting thing to try!
I&amp;rsquo;ve decided to go with &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt; for this one, to further reduce friction, as this game engine/fantasy console has everything I need to design a game.&lt;/p&gt;
&lt;p&gt;In the previous post, I also mentioned that I was traveling, and while I wasn&amp;rsquo;t able to get to my laptop at all, I&amp;rsquo;ve decided that I will allow myself to draw some sprites for the upcoming game in advance.
The only problem was that I had to do it on my phone, which is a challenge on its own, and I don&amp;rsquo;t know what software to use.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried a bunch of options, and settled with &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.PixelStudio&#34; target=&#34;_blank&#34;&gt;PixelStudio&lt;/a&gt; by &lt;a href=&#34;https://github.com/hippogamesunity&#34; target=&#34;_blank&#34;&gt;hippogamesunity&lt;/a&gt;.
Sadly, it&amp;rsquo;s not open source, but it is common for a lot of software for pixel art, and art in general.
The only open-source free software pixel art app I know is &lt;a href=&#34;https://libresprite.github.io/#!/&#34; target=&#34;_blank&#34;&gt;LibreSprtie&lt;/a&gt;, which itself is a fork of &lt;a href=&#34;https://www.aseprite.org/&#34; target=&#34;_blank&#34;&gt;Aseprite&lt;/a&gt; which changed its license some years ago and is no longer FOSS.
Since I was considering paying for either of those, I decided to go with PixelStudio because my phone has a stylus (S-Pen) that is supported by the app, and drawing on the screen seemed nicer.
I can always bring LibreSprite on my laptop in case I need more, and TIC also has a sprite editor.
TIC is also available on the phone, but unlike TIC, PixelStudio gives me the ability to do animations, which is what I was mainly looking for.
If not for animations, I would probably stick with the phone version of TIC until I&amp;rsquo;ve returned.&lt;/p&gt;
&lt;p&gt;So I went on and started working on characters for my &lt;code&gt;Game1&lt;/code&gt; project.
&lt;code&gt;Game1&lt;/code&gt; is, of course, a work-in-progress title, but it&amp;rsquo;s not far from the truth, as this will probably be the first thing that I will consider something like a real game made by me.
Anyway, this is how the app in which I drew my character looks:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2023-06-30-game1/pixelstudio.jpg&#34; width=&#34;35%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The interface is a bit cluttered, but I find it useful enough if the screen is big enough, which is my case.
But, back on character animations, here&amp;rsquo;s what I&amp;rsquo;ve got so far:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-06-30-game1/moveset.gif&#34; width=&#34;100%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is just a mockup, testing around how animations would look in-game.
The blue fireball was added to show the damage animation, I&amp;rsquo;m not even sure if the projectiles will be in the game.
And starting from tomorrow I will actually start putting things together in the TIC.
I&amp;rsquo;m now realizing that by using too much color in the character sprite, I kinda limited myself on the number of colors that I can use for the background, and terrain because the default palette in TIC is quite limited on colors:&lt;/p&gt;
&lt;figure class=&#34;pixelart&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-06-30-game1/sweetie-16.png&#34; width=&#34;100%&#34; height=&#34;auto&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;So I may need to do a bit of redesign on the character part.
Actually, I&amp;rsquo;ve always liked pixel art for its limiting nature - the ability to express a lot of ideas and small details in such a low amount of pixels and colors always fascinated me.
I don&amp;rsquo;t know much about pixel art, and it probably shows, but hey, this marathon is to learn new stuff, so give me some time!
But, right now I&amp;rsquo;m not even sure how do I program such animations, so I&amp;rsquo;ll probably start with just drawing a rectangle for the player, enemies, and platforms.&lt;/p&gt;
&lt;p&gt;I will be posting updates as soon as I get more progress, so expect this as a kind of dev-log, but honestly, it is mostly for me, as I find this kind of activity encouraging to keep on.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;You&amp;rsquo;re welcome to join, of course, but I&amp;rsquo;m not going to organize an actual event&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Game1&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 30 Jun 2023 22:46:00 +0300</pubDate>
    </item><item>
      <title>The key point of Emacs</title>
      <link>https://andreyor.st/posts/2023-06-12-the-key-point-of-emacs/</link>
      <guid>https://andreyor.st/posts/2023-06-12-the-key-point-of-emacs/</guid>
      <description>&lt;p&gt;Lately, I&amp;rsquo;ve been reflecting on why I&amp;rsquo;ve settled with Emacs of all other text editors.
You may remember my old &lt;a href=&#34;https://andreyor.st/posts/2020-04-29-text-editors/&#34;&gt;post&lt;/a&gt; where I go into lots of different &lt;em&gt;code&lt;/em&gt; editors, and I list Emacs among them too.
That post itself was written in Emacs, like everything else in this blog, but I can&amp;rsquo;t say that I understood the main point of Emacs back then.
Err, I don&amp;rsquo;t think I do now, hence the post doesn&amp;rsquo;t use &amp;ldquo;main point&amp;rdquo; in the name, but it feels that I&amp;rsquo;m getting closer.&lt;/p&gt;
&lt;p&gt;Each editor has its own philosophy that kinda sells it to you.
Like, Vim&amp;rsquo;s keyboard-oriented editing language, where you execute actions on text objects or Kakoune&amp;rsquo;s similar but inverted model of selecting objects first, then operating on them, or even on multiple objects at once.
Visual Studio Code has out-of-the-boxiness and user-friendliness paired with a rich amount of extensions, modern and beautiful interface with rich rendering capabilities.
Sublime Text&amp;rsquo;s speed, and so on.&lt;/p&gt;
&lt;p&gt;But what&amp;rsquo;s the philosophy of Emacs?
Emacs doesn&amp;rsquo;t have an editing language like Vim&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, it&amp;rsquo;s not as user-friendly as VSCode or Atom, its interface is far from modern, and rendering capabilities are kinda limited.
One might say it&amp;rsquo;s extensibility, but I don&amp;rsquo;t think it&amp;rsquo;s a proper term here.
VSCode, Sublime Text, and Vim can be extended with new features as well.
Another point I often hear is that you can make Emacs &amp;ldquo;your own&amp;rdquo;.
Well, so can be done with Vim, and people go to great lengths to do it with VSCode or Sublime.&lt;/p&gt;
&lt;p&gt;I think the key point is that Emacs isn&amp;rsquo;t really just an editor - it&amp;rsquo;s a platform.
It doesn&amp;rsquo;t really matter what extension language Emacs uses, and it doesn&amp;rsquo;t really matter if Emacs has millions of packages, as all other editors do.
What does matter is that Emacs is a platform that allows its users not only to extend it with new features, but also change how it operates at runtime.
Emacs Lisp is great for that purpose because it was basically developed as a system-level language for the Emacs system.
All of the system&amp;rsquo;s functions are available to you as a user, and you can do whatever you want with them, down to the core.
And while its core is written in C, nothing prevents you from calling these C functions from Emacs Lisp, much like you can do from the system language of your operating system.&lt;/p&gt;
&lt;p&gt;I think that&amp;rsquo;s what differentiates Emacs from most other software I use, and I think it&amp;rsquo;s a great model.
It kinda makes me think about Emacs as a Smalltalk system, which isn&amp;rsquo;t just a language, but an image that you can operate on.
And it matches how Emacs Lisp is tied to Emacs itself, and I don&amp;rsquo;t really think it is really worth decoupling one from another because Emacs Lisp isn&amp;rsquo;t the greatest Lisp out there, to be honest.&lt;/p&gt;
&lt;p&gt;Sadly, unlike Smalltalk, Emacs&amp;rsquo; GUI system is far less advanced.
You take &lt;a href=&#34;https://pharo.org/&#34; target=&#34;_blank&#34;&gt;Pharo&lt;/a&gt; or &lt;a href=&#34;https://squeak.org/&#34; target=&#34;_blank&#34;&gt;Squeak&lt;/a&gt;, and it comes with a graphical interface with proper buttons, widgets, and so on.
Then you look at things like &lt;a href=&#34;https://gtoolkit.com/&#34; target=&#34;_blank&#34;&gt;GToolkit&lt;/a&gt;, which is based on Pharo, and begin to question yourself, why can&amp;rsquo;t we have something like this in Emacs?
All these custom inspectors as they call them in GToolkit allowing you to interact with graphs, images, and even data structures are really nice to have&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also another technology that acts similarly, although I can&amp;rsquo;t say it has the same level of integration with its core as Emacs or Smalltalk do.
I&amp;rsquo;m talking about &lt;a href=&#34;https://www.electronjs.org/&#34; target=&#34;_blank&#34;&gt;Electron&lt;/a&gt;, the technology behind Atom, VSCode, and a lot of other software.
I hope you can see why I think it is somewhat similar to Emacs - as it is a dynamic runtime system that runs on a pretty advanced core, but in this case, the core isn&amp;rsquo;t just a virtual machine, it&amp;rsquo;s a full-blown browser (though it is stripped down, a bit).
Browser&amp;rsquo;s rendering capabilities are impressive, and support for all kinds of formats is also great, which makes it a nice target to base user applications on.
Though, it&amp;rsquo;s more limited than Emacs, because you basically only have the Electron API, and you can&amp;rsquo;t go lower (correct me if I&amp;rsquo;m wrong).
And because of this limitation, I can&amp;rsquo;t think of VSCode as I think of Emacs, though Atom was so close to it, as their approach to the whole structure of the program was a lot more modular.&lt;/p&gt;
&lt;p&gt;Speaking of GUI, Emacs is limited to text buffers and basic overlays.
Sure, that can make it look like Emacs has some kind of widgets, but it doesn&amp;rsquo;t feel like interacting with a widget, as you still insert text into the text buffer basically.
Some &lt;a href=&#34;https://github.com/rougier/nano-emacs#experimental&#34; target=&#34;_blank&#34;&gt;projects&lt;/a&gt; even incorporate SVG rendering to make Emacs look more modern, I tried this &lt;a href=&#34;https://andreyor.st/2023-06-12-the-key-point-of-emacs/emacs.png&#34;&gt;too&lt;/a&gt;, but it still feels not as a real GUI app.
Developing a set of GUI widgets is a hard task, and interfaces came a really long way since Emacs&amp;rsquo; inception, and things like Smalltalk were basically aimed at graphical interfaces from the start so the comparison isn&amp;rsquo;t really fair.
Though, a lot of people argue that a proper GUI will make it hard to use Emacs from the terminal, to which I would say that it&amp;rsquo;s fair, but also why?
And a lot will argue that Emacs&amp;rsquo; text-oriented interface is &lt;em&gt;better&lt;/em&gt; because it allows using the same set of functions for both text manipulation and interface manipulation (because it&amp;rsquo;s the same thing).
I don&amp;rsquo;t think it&amp;rsquo;s a good design though, as it is basically re-purposing text editing features into a rendering engine which, while works, still makes me think that it would be nice to see a proper GUI implemented in Emacs.&lt;/p&gt;
&lt;p&gt;Despite all of that, people basically live in Emacs.
I do as well.
I read and write mail, work on this blog, chat in IRC, working with Git, browse remote servers, read books, do planning, browse RSS feeds, and do lots of other minute tasks that I can&amp;rsquo;t really remember right now.
All without opening a terminal, because with Emacs I don&amp;rsquo;t need one.
What I&amp;rsquo;m trying to say here is that I don&amp;rsquo;t really need Emacs to be compatible with terminals, because, as I said, you can open Emacs SSH from it, you don&amp;rsquo;t really need to be able to SSH somewhere and open Emacs there, as a lot of people do with Vim.
So a proper GUI won&amp;rsquo;t hurt Emacs in my opinion, because there&amp;rsquo;s no reason to run Emacs in the terminal at all.&lt;/p&gt;
&lt;p&gt;And the thing is, I believe it is possible to implement a proper GUI in Emacs because, unlike in many other software, you can extend Emacs down to the core.
And that&amp;rsquo;s why I love it, and I actually use it, changing the behavior of built-in packages to suit my needs, and creating helper functions to enhance the overall experience.
For now, I can&amp;rsquo;t see myself leaving this ecosystem for something else, and Emacs is rapidly evolving, I think in the last three years there were more new exciting features than in the last five years before it.
Maybe a proper GUI system will come as well, who knows?
Or maybe a new &lt;a href=&#34;https://project-mage.org/emacs-is-not-enough&#34; target=&#34;_blank&#34;&gt;rival&lt;/a&gt; appears, that realized what makes Emacs great, but also realized that there are still a lot of things to improve on in this model.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;rsquo;ve drifted from the main topic of this post.
The thing is, it&amp;rsquo;s not just about extensibility or ability to make Emacs your own - a lot of software can do that.
It&amp;rsquo;s about being a platform that gives you all the tools you need to build upon.
Which Emacs really excels at, in my opinion.
Thanks for reading.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Although nothing prevents you from implementing one.
Some even say that Emacs&amp;rsquo; Vim emulation is better than the real thing.
True, Emacs&amp;rsquo; default editing experience isn&amp;rsquo;t the greatest, still, a lot of users stick to it and improve the main pain points based on their personal needs.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I work with Clojure a lot, and an advanced inspector that would allow me to navigate deep data structures would be a blast.
And while CIDER has it, the experience is not as nice as it could have been.
I&amp;rsquo;ve even tried using &lt;a href=&#34;https://github.com/djblue/portal&#34; target=&#34;_blank&#34;&gt;Portal&lt;/a&gt; which &lt;a href=&#34;https://github.com/djblue/portal/blob/master/doc/editors/emacs.md&#34; target=&#34;_blank&#34;&gt;comes with support for xwidgets&lt;/a&gt;, but it still isn&amp;rsquo;t a great experience, because &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Xwidgets.html&#34; target=&#34;_blank&#34;&gt;Xwidgets&lt;/a&gt;, while integrated into Emacs window system, is still foreign, and what&amp;rsquo;s displayed there can&amp;rsquo;t be controlled like Emacs.
That&amp;rsquo;s why I think a proper GUI would be a better fit.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: The key point of Emacs&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 12 Jun 2023 23:32:00 +0300</pubDate>
    </item><item>
      <title>Trusting LLMs</title>
      <link>https://andreyor.st/posts/2023-06-11-trusting-llms/</link>
      <guid>https://andreyor.st/posts/2023-06-11-trusting-llms/</guid>
      <description>&lt;p&gt;Recently I had a discussion on the topic of trust and it got me thinking about large language models.
I will come back to LLMs shortly, but imagine the situation:&lt;/p&gt;
&lt;p&gt;You ask a real person for some bit of information, and the information they&amp;rsquo;ve provided to you is false but you don&amp;rsquo;t know it yet.
After wasting some of your time, and realizing that the information wasn&amp;rsquo;t correct, or even malicious you get back to the person and tell them that.
The response highly depends on the person, and on their intentions, but what I&amp;rsquo;m trying to say is that people can &lt;em&gt;lie&lt;/em&gt;, often unconsciously.
&amp;ldquo;Unconscious lie&amp;rdquo; isn&amp;rsquo;t really a lie in a traditional sense, often it&amp;rsquo;s just caused by misremembering something, but it&amp;rsquo;s sometimes hard to draw a line when a person just misremembers something, or they have some malicious intent.&lt;/p&gt;
&lt;p&gt;So, if a person gives you misinformation over and over again, your trust credit for them drops pretty quickly, and in the future, you usually avoid asking them anything.
And that brings us back to large language models.&lt;/p&gt;
&lt;p&gt;LLMs usually don&amp;rsquo;t have any intent of misinformation, but they drift quite often, especially when you&amp;rsquo;re exploring an area that had a lot less training data, compared to other areas.
If you ever tried asking ChatGPT for help with some not-so-popular programming languages, you may have noticed that the examples often are complete gibberish containing syntax from a completely different language or just non-existing functions.
But why doesn&amp;rsquo;t our trust credit for LLMs drops like it does when we&amp;rsquo;re talking with a real person? And why we don&amp;rsquo;t assume that LLM can in fact have malicious intents?&lt;/p&gt;
&lt;p&gt;What I often think about is that LLMs are created by big corporations, because this kind of work requires a lot of funding.
And such corporations can, and in fact often have, specific intentions, one of which is expanding their reach in the global market.
Not so long ago a lot of people talked about how Google is scared by ChatGPT because soon no one will now use their search engine, which they use for advertising.
But no one talked about how ChatGPT can be used for advertising, for some reason.&lt;/p&gt;
&lt;p&gt;What I mean is that once the technology behind LLMs is widespread enough, it will have advertisements integrated into the text probably much better than when Google integrates ads into their search results.
And when asking LLM a question, we&amp;rsquo;ll have to remember, that LLM may in fact try to advertise something that we don&amp;rsquo;t really want.
Or, it may straight up generate a response that diminishes one product while comparing it to another.
And so forth.&lt;/p&gt;
&lt;p&gt;I think a lot of this comes from the fact that we know that LLM is not a real human, and it has a limited amount of knowledge.
That it is a relatively new breakthrough in natural language-related tech, and it can give faulty responses because of that.
But because things are changing gradually, we may not notice the moment when these seemingly accidental faults will become intentional.
Because despite the fact that the model gave us a wrong answer we still come back to it, which we probably wouldn&amp;rsquo;t do if it wasn&amp;rsquo;t a model but a human person.&lt;/p&gt;
&lt;p&gt;So my thinking here is that we should not give LLMs a discount when it comes to our trust credit.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Trusting LLMs&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 11 Jun 2023 23:06:00 +0300</pubDate>
    </item><item>
      <title>Gamedev plans</title>
      <link>https://andreyor.st/posts/2023-06-09-gamedev-plans/</link>
      <guid>https://andreyor.st/posts/2023-06-09-gamedev-plans/</guid>
      <description>&lt;p&gt;I like playing games, but I was always interested in making games too.
Recently a Lisp game jam ended, and there are a lot of cool entries, and its a shame I wasn&amp;rsquo;t able to participate, as I was traveling.
And last year I participated in the &lt;a href=&#34;https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/&#34;&gt;Fennel Game Jam 1&lt;/a&gt;, which was my first game jam, and while the game I made wasn&amp;rsquo;t anything special, it was a really fun experience.
Though, I usually don&amp;rsquo;t participate in such jams either because the time is inconvenient for me, or because the time restriction or theme is way ahead of my skill level.
But I still want to get into game development, and I&amp;rsquo;ve decided that if I don&amp;rsquo;t start now, it will be too late.&lt;/p&gt;
&lt;p&gt;So this post is both an announcement of a new series of posts and also something to motivate me not to give up the idea.&lt;/p&gt;
&lt;p&gt;Starting next month (because I&amp;rsquo;m still traveling), I will try to make &lt;strong&gt;one small game per month&lt;/strong&gt;.
Nothing is set in stone yet, but I&amp;rsquo;m imagining the following types of games:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Platformer
&lt;ul&gt;
&lt;li&gt;Small, old-school style, run and jump&lt;/li&gt;
&lt;li&gt;6-9 stages at most&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dungeon crawler or roguelike
&lt;ul&gt;
&lt;li&gt;Procedural generation&lt;/li&gt;
&lt;li&gt;Interactivity with the environment&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Card game
&lt;ul&gt;
&lt;li&gt;Deck builder?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Puzzle platformer
&lt;ul&gt;
&lt;li&gt;Time-based or switch-based puzzles&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Top-down adventure
&lt;ul&gt;
&lt;li&gt;semi-open-world map, like in old Zeldas&lt;/li&gt;
&lt;li&gt;Character interactions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All games will probably be 2D and made with rather simple graphics and sounds, that I will also try to make myself.
At the end of each month, I will release the complete game code and assets and will write a small post outlining the development process.
To be honest, I&amp;rsquo;m a bit tired of writing libraries, and while I was looking at my projects directory, I noticed how many of my projects are just that.
So I&amp;rsquo;ve decided to force myself into a new field, to learn some new technologies, and maybe try out various game engines and languages, so we&amp;rsquo;ll see.&lt;/p&gt;
&lt;p&gt;As of this moment, I&amp;rsquo;m thinking mostly about making games with &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt; and &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;LÖVE2D&lt;/a&gt;.
Both are really simple engines, and both use the language I already know pretty well.
However, I also would like to try out a different game engine, such as &lt;a href=&#34;https://defold.com/&#34; target=&#34;_blank&#34;&gt;Defold&lt;/a&gt;, or &lt;a href=&#34;https://godotengine.org/&#34; target=&#34;_blank&#34;&gt;Godot&lt;/a&gt;, so maybe expect something made with these, I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;You see, I have a few very particular games I wanted to make for quite some time, and for the last few years, I&amp;rsquo;ve made some notes on various ideas I had regarding these games.
So my plan right now is to make a few smaller games, that utilize many of the mechanics that I will later need for these larger games, thus making it easier for future me to implement them in the correct way.
And while these small games will definitively not be the best games, I hope they will still be enjoyable, or at the very least finished and playable.&lt;/p&gt;
&lt;p&gt;Maybe I&amp;rsquo;m overestimating my abilities, and one month per game will not be enough for me, but I&amp;rsquo;ll never know if I don&amp;rsquo;t try.
I will be publishing these posts under the &lt;a href=&#34;https://andreyor.st/categories/gamedev/feed.xml&#34;&gt;gamedev&lt;/a&gt; category (each category on my blog has its own feed you can subscribe to if you&amp;rsquo;re interested).&lt;/p&gt;
&lt;p&gt;I hope it will be a fun experiment!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Gamedev plans&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 09 Jun 2023 22:15:00 +0300</pubDate>
    </item><item>
      <title>Clojure&#39;s core.async port for the Fennel language</title>
      <link>https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/</link>
      <guid>https://andreyor.st/posts/2023-05-15-clojures-coreasync-port-for-the-fennel-language/</guid>
      <description>&lt;p&gt;After I explored asynchronous programming in my first naive implementation &lt;a href=&#34;https://andreyor.st/posts/2021-10-27-naive-async-implementation-in-fennel/&#34;&gt;a few years ago&lt;/a&gt;, I was hooked on the idea of asynchronous communication in programs.
Motivated to take this concept further I&amp;rsquo;ve created the &lt;a href=&#34;https://github.com/andreyorst/fennel-async&#34; target=&#34;_blank&#34;&gt;fennel-async&lt;/a&gt; library that I&amp;rsquo;ve shown &lt;a href=&#34;https://conf.fennel-lang.org/2022&#34; target=&#34;_blank&#34;&gt;at FennelConf 2022&lt;/a&gt;.
While this library works, and I&amp;rsquo;ve managed to write a simple socket-based REPL and integrate it into Emacs as an experiment, I wasn&amp;rsquo;t satisfied with the implementation.
Mainly because the library is pull-based, which means that the tasks are &lt;em&gt;pulled&lt;/em&gt; by the continuously running scheduler.
It poses some difficulties in Lua runtime, as there&amp;rsquo;s no support for multithreading, and the scheduler can&amp;rsquo;t be offloaded to a separate thread.
I soon realized that a proper asynchronous system is push-based, meaning that pushing to the task triggers its activation.
With that in mind I&amp;rsquo;ve started working on a newer version of the library: &lt;a href=&#34;https://github.com/andreyorst/async.fnl&#34; target=&#34;_blank&#34;&gt;async.fnl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The library started as a small channel-based communication system, where each channel had its own queue of puts, a queue of takes, and an optional buffer, much like &lt;a href=&#34;https://github.com/clojure/core.async&#34; target=&#34;_blank&#34;&gt;core.async from Clojure&lt;/a&gt;.
I was planning to only implement &lt;code&gt;put!&lt;/code&gt;, &lt;code&gt;take!&lt;/code&gt; and &lt;code&gt;alts!&lt;/code&gt; operations, as these are the bare minimum that is needed for the library to be functional, as everything else is bootstrapped on them.
However, it was hard to test the library this way, so I started adding more and more operations, like &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;into&lt;/code&gt;, eventually added the support for transducers, and before I knew it I was thinking about how to port &lt;code&gt;Mult&lt;/code&gt;, &lt;code&gt;Mix&lt;/code&gt;, and &lt;code&gt;Pub&lt;/code&gt;.
At that moment I decided that I will simply port everything from the &lt;code&gt;core.async&lt;/code&gt;, including tests, and that&amp;rsquo;s where my implementation of channels started failing.
So I ported the channels too.&lt;/p&gt;
&lt;p&gt;Now this library is a mostly complete port of the ClojureScript version of the library.
The reason I&amp;rsquo;ve chosen ClojureScript as a base is that it is also a single-threaded system, so it should behave similarly to Lua, which Fennel uses as its target for compilation.
Interestingly enough, and you don&amp;rsquo;t have to believe me&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, but up until I decided to port the tests, and later the channel implementation, I was writing this library without looking at the &lt;code&gt;core.async&lt;/code&gt; source code and the resulting Fennel code was quite similar.
Well, this is largely due to the fact that channels are well covered by Rich Hickey in &lt;a href=&#34;https://youtu.be/yJxFPoxqzWE&#34; target=&#34;_blank&#34;&gt;his talk&lt;/a&gt;, and I&amp;rsquo;ve already made three wrong implementations of them, so I knew what I need to do now for the most part.
I&amp;rsquo;m also a bit familiar with Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; code, but only with the public API.
I&amp;rsquo;ve never looked into the implementation of channels, as my tinkering with the library only needed to go as far as the implementation of pipelines, which I&amp;rsquo;ve covered in my post about &lt;a href=&#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/&#34;&gt;fixing the off-by-two error&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So when the tests started to fail, I knew that something wasn&amp;rsquo;t right, so after some hours of debugging I ditched my own implementation of channels and ported the code from ClojureScript into Fennel.
This was a fun experience, and I&amp;rsquo;ve even &amp;ldquo;ported&amp;rdquo; &lt;code&gt;reify&lt;/code&gt; and &lt;code&gt;defprotocol&lt;/code&gt; just not to think too much about how to write it manually in every function.
I&amp;rsquo;ve put ported in quotes because it&amp;rsquo;s not a true port, just a similar macro that expands to the runtime definition of an object that conforms to the &lt;code&gt;defprotocol&lt;/code&gt; spec:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defprotocol&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;faccumulate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt; {} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected method declaration&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;method&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected named method&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected arglist for method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected no body for method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;methods&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) `#(&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;)))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reify&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocols&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;actions&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;do&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected symbol or fnspec&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.insert &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocols&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &amp;amp; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fnspec&lt;/span&gt;]] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected method name&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected method arglist&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.insert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;actions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              `(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f#&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arglist&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unpack &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fnspec&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;arity mismatch for method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:_&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Protocol &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; doesn&amp;#39;t define method &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not= &lt;/span&gt;0 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;select &lt;/span&gt;&lt;span style=&#34;&#34;&gt;:&lt;/span&gt;# &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt; {}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;actions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setmetatable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reify&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__fennelview&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         #(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#&amp;lt;&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;table:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;reify:&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; &lt;span style=&#34;&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocols&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;)}))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a little messy but works fine.
I added it when I was porting &lt;code&gt;Mult&lt;/code&gt;, which looks a lot like the ClojureScript version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defprotocol&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;muxch&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defprotocol&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap-all&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mult&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Creates and returns a mult(iple) of the supplied channel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`ch`.  Channels containing copies of the channel can be created with
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;tap&amp;#39;, and detached with &amp;#39;untap&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Each item is distributed to all taps in parallel and synchronously,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;i.e. each tap must accept before the next item is distributed.  Use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;buffering/windowing to prevent slow taps from holding up the mult.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Items received when there are no taps get dropped.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;If a tap puts to a closed channel, it will be removed from the mult.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;var &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; {}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;muxch&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Mult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;untap-all&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;tset &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cs&lt;/span&gt; {}) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dchan&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dchan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom.cs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom.cs&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dctr&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;length &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:untap&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dchan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sure, fennel doesn&amp;rsquo;t have sequences and atoms by default, so this uses mutable tables, but the semantics are the same.&lt;/p&gt;
&lt;p&gt;In general, Fennel isn&amp;rsquo;t exactly compatible with Clojure, as it is a different language.
There&amp;rsquo;s no arity overloading, data structures aren&amp;rsquo;t persistent, and there are no lazy sequences, only iterators over tables.
All these features can be implemented as libraries, and I&amp;rsquo;ve already made &lt;a href=&#34;https://andreyor.st/about#clojure-libraries-for-fennel&#34;&gt;a bunch&lt;/a&gt; that should make a Clojure programmer feel more at home.
Well, at least the strings are immutable by default, which is good!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve chosen the same versioning scheme as the Clojure version of the library, but it is still in an experimental state.
More tests should be added, I also need to test on different runtimes, as this is only tested to work on Lua 5.4 at the moment.&lt;/p&gt;
&lt;h2 id=&#34;differences-from-the-clojure-version&#34;&gt;Differences from the Clojure version&lt;/h2&gt;
&lt;p&gt;One tricky thing this library requires is the presence of the &lt;code&gt;debug&lt;/code&gt; Lua library.
It is included by default in most Lua implementations, but it may be absent in an embedded Lua.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;debug&lt;/code&gt; library is required to run timers.
By using the &lt;code&gt;debug.sethook&lt;/code&gt; function, when the library is loaded, a hook that checks if any of the timeout channels have expired runs every 1000 Lua instructions, and on each function return.
This needs a bit more profiling to get an optimal amount of instructions between runs, but the tests show a nice accuracy with the error of 10ms, which is largely due to the library trying to minimize the number of timeout channels by rounding their duration to these 10ms.
It&amp;rsquo;s similar to what the Clojure version does, e.g. the expression &lt;code&gt;(= (timeout 1000) (timeout 1000))&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; because only one timeout channel is created under the hood.
When the &lt;code&gt;debug&lt;/code&gt; library is unavailable, the &lt;code&gt;timeout&lt;/code&gt; function throws an error, but the rest of the library should work fine, as timeout channels aren&amp;rsquo;t used anywhere.&lt;/p&gt;
&lt;p&gt;Another tricky thing is that Lua by default doesn&amp;rsquo;t support sub-second precision for measuring time.
The default &lt;code&gt;os.time&lt;/code&gt; reports the number of seconds since the epoch, and there&amp;rsquo;s no way to get the number of milliseconds.
The solution is to check if the &lt;code&gt;luasocket&lt;/code&gt; or &lt;code&gt;luaposix&lt;/code&gt; libraries are present on the &lt;code&gt;LUA_PATH&lt;/code&gt;.
If so, their implementations of the &lt;code&gt;gettime&lt;/code&gt; function are used, which gives millisecond precision.
Otherwise, the number of milliseconds passed to the &lt;code&gt;timeout&lt;/code&gt; function is rounded up to the next whole second.
Not ideal, but works, especially since the asynchronous code shouldn&amp;rsquo;t be too dependent on specific timings.
The library will warn you if you don&amp;rsquo;t have any of these installed.&lt;/p&gt;
&lt;p&gt;And the final difference from Clojure is that there is no inversion of control (IOC) transformations involved.
Lua, unlike the JVM, supports sackful coroutines, which means that any function can be turned into coroutines that can be stopped and resumed with the &lt;code&gt;coroutine.yield&lt;/code&gt; call.
Thus, all operations that would result in a blocking behavior, like &lt;code&gt;&amp;lt;!&lt;/code&gt; or &lt;code&gt;&amp;gt;!&lt;/code&gt;, actually just capture the running thread with the &lt;code&gt;coroutine.running&lt;/code&gt; put it to the respective queue on the channel where the operation occurs, and the channel calls &lt;code&gt;coroutine.yield&lt;/code&gt;.
Next, when this channel receives another put or takes if there&amp;rsquo;s a such pending thread, it will be resumed with the value of the operation.
Stackful coroutines make the implementation much simpler, without the need to write complex macros that transform the code into state machines.
I wish more languages had them, as it is a great feature that can be used in a variety of ways.
Generators are cool, but Lua coroutines are much cooler.
But I digress.&lt;/p&gt;
&lt;h2 id=&#34;future-plans&#34;&gt;Future plans&lt;/h2&gt;
&lt;p&gt;Overall, this was a fun experiment, and while I really like asynchronous programming, I feel that I need to stop myself here.
There are a lot of other topics I want to get into, like the bytecode VM design, gamedev, and other cool stuff.
So hopefully there will be no more async shenanigans from me.
Though, maybe I&amp;rsquo;ll try to port the TCP module from &lt;code&gt;fennel-async&lt;/code&gt; into this library, but we&amp;rsquo;ll see.
That may be difficult, as there&amp;rsquo;s no way to register a callback on a socket object with the &lt;code&gt;luasocket&lt;/code&gt; library, which almost defeats the purpose of being push-based.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using Fennel, and you&amp;rsquo;re familiar with &lt;code&gt;core.async&lt;/code&gt; do give this library a test.
I&amp;rsquo;m curious how it will work in other programs because I&amp;rsquo;m making all these libraries, but I don&amp;rsquo;t really have any time to use them as parts of other projects, besides maybe the &lt;a href=&#34;https://github.com/andreyorst/fenneldoc&#34; target=&#34;_blank&#34;&gt;fenneldoc&lt;/a&gt;, which uses the &lt;code&gt;cljlib&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;Anyway, thanks for reading, and I hope this library will be useful!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;You don&amp;rsquo;t have to, but if you read my blog, you may remember that that&amp;rsquo;s the way I usually like to do stuff.
Diving in without any or very little amount of prior knowledge on the topic and thinking about how would I implement that.
And if the result is similar to the reference implementation or differs from it, that&amp;rsquo;s how I know if I made any mistakes, or if my assumptions were correct.
This library started the same way.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure&#39;s core.async port for the Fennel language&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 15 May 2023 22:44:00 +0300</pubDate>
    </item><item>
      <title>New Fennel Proto REPL and call for testing</title>
      <link>https://andreyor.st/posts/2023-04-08-new-fennel-proto-repl-and-call-for-testing/</link>
      <guid>https://andreyor.st/posts/2023-04-08-new-fennel-proto-repl-and-call-for-testing/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/&#34;&gt;previous post&lt;/a&gt; I&amp;rsquo;ve described how to define a simple protocol, upgrade the stock Fennel REPL with it, and create a simple client that works with this setup.
And at the end, I mentioned that I was working on a proper client implementation and a more robust protocol as part of the &lt;code&gt;fennel-mode&lt;/code&gt; package.
So today I&amp;rsquo;m presenting the new &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode/tree/dd2d0845cd8f21f6487c4e8ca5ea104d1fcba11a/item/fennel-proto-repl.el&#34; target=&#34;_blank&#34;&gt;fennel-proto-repl&lt;/a&gt; module!&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s an experimental implementation of the new Fennel REPL client, that is based on the message-callback system, and it provides more robust ways of communicating with the REPL process.
We&amp;rsquo;re not going to remove the old REPL integration support, and it going to remain the default one since I expect that some rough edges still need to be refined, and we still need to wait until Fennel will release the next stable version anyway.
But if you&amp;rsquo;re using the development version of Fennel or don&amp;rsquo;t mind trying things, you can update &lt;code&gt;fennel-mode&lt;/code&gt; and try the new REPL implementation by adding the following hook to your Emacs configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;fennel-mode-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;fennel-proto-repl-minor-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This new minor mode enables the integration with the new REPL implementation, meaning that all usual commands, such as &lt;kbd&gt;Ctrl+Alt+x&lt;/kbd&gt; (&lt;code&gt;eval-defun&lt;/code&gt;) will use the new REPL implementation.&lt;/p&gt;
&lt;p&gt;At the end of the previous post I mentioned that the protocol-based REPL may not work in all cases, but this limitation should now be lifted in the latest Fennel (that&amp;rsquo;s why the Fennel update is required).
I&amp;rsquo;ve &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel/commit/8adeaad80ab93ba86216c255eda355e99c61b53a&#34; target=&#34;_blank&#34;&gt;sent a patch&lt;/a&gt; that makes inbuilt Fennel REPL more dynamic, and now the currently running REPL can be changed at runtime.
Thus, if your application uses a custom REPL, like the one in the &lt;a href=&#34;https://gitlab.com/alexjgriffith/min-love2d-fennel/-/blob/ecce4e3e802b3a85490341e13f8c562315f751d2/lib/stdio.fnl&#34; target=&#34;_blank&#34;&gt;min-love2d-fennel repo&lt;/a&gt;, you should be able to use new Proto REPL, you&amp;rsquo;ll just need to update the Fennel dependency in your application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So this post is a call for testing!&lt;/strong&gt;
If you experience hiccups or problems with the stock &lt;code&gt;fennel-repl&lt;/code&gt; mode in Emacs, give &lt;code&gt;fennel-proto-repl&lt;/code&gt; a try!&lt;/p&gt;
&lt;h2 id=&#34;what-s-new&#34;&gt;What&amp;rsquo;s new&lt;/h2&gt;
&lt;p&gt;Here I&amp;rsquo;ll briefly list enhancements that are now possible thanks to the protocol.
There aren&amp;rsquo;t a lot of new features, the new client mostly provides stability-related improvements, yet, there are some things I&amp;rsquo;d like to note.&lt;/p&gt;
&lt;h3 id=&#34;programmatic-api&#34;&gt;Programmatic API&lt;/h3&gt;
&lt;p&gt;First of all, now it is possible to send both synchronous and asynchronous messages to the REPL process and use a system of callbacks to get back the results.
Previously it was possible but it was quite finicky because of how comint&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; works, and thus all requests sent outside of the REPL were synchronous (like completions or documentation fetching).
Again, I&amp;rsquo;ve &lt;a href=&#34;https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/#comint&#34;&gt;described it in detail&lt;/a&gt; in the previous post.
The REPL itself is still synchronous - all messages are processed sequentially, but the client is now decoupled and doesn&amp;rsquo;t have to proactively wait for each message to be processed.&lt;/p&gt;
&lt;p&gt;The new API includes these two functions: &lt;code&gt;fennel-proto-repl-send-message&lt;/code&gt;, and &lt;code&gt;fennel-proto-repl-send-message-sync&lt;/code&gt;.
The first one will never block Emacs and should be used whenever you want to send some code to the REPL but you don&amp;rsquo;t require the result immediately.
Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(+ 1 2 3)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%S&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, the result will be shown when the REPL is ready to process the message.
You can additionally provide error callback and printing callback to capture error messages or data that the REPL requested to print.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-proto-repl-send-message-sync&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(+ 1 2 3)&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; (&amp;#34;6&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will block Emacs until the REPL is ready to process the message, so it should be used with care.
The message, however, can timeout after a configurable amount of time (5 seconds by default), so the block will not be indefinite.&lt;/p&gt;
&lt;p&gt;Most of the features in the new client are implemented via these two functions, so it should be enough for other packages to integrate with the new client if necessary.
I&amp;rsquo;m already thinking about updating my &lt;a href=&#34;https://gitlab.com/andreyorst/ob-fennel&#34; target=&#34;_blank&#34;&gt;ob-fennel&lt;/a&gt; package to use this new REPL implementation, as it will fix a lot of bugs and problems in general.&lt;/p&gt;
&lt;h3 id=&#34;multiple-repls&#34;&gt;Multiple REPLs&lt;/h3&gt;
&lt;p&gt;Support for multiple REPL sessions received some improvements.
Previously, with the comint-based REPL, in order to have more than one REPL active at a time, it was required to rename the existing REPL buffer, and then start a new one.
Otherwise, the function that starts the REPL just jumped to the already running one.
This worked, however, the in-buffer commands, such as &lt;code&gt;eval-defun&lt;/code&gt; or &lt;code&gt;eval-last-sexp&lt;/code&gt; started working with the new REPL buffer unless it also was renamed.
If there wasn&amp;rsquo;t a REPL buffer with the default name these commands didn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;Fennel Proto REPL introduces a way to link a certain buffer to a certain REPL with the &lt;code&gt;fennel-proto-repl-link-buffer&lt;/code&gt; function.
This function provides a list of currently running REPLs to choose from, and after choosing one all in-buffer commands start working with that REPL.
Additionally to that, it&amp;rsquo;s no longer necessary to manually rename the REPL buffer to start a new one - the &lt;code&gt;fennel-proto-repl&lt;/code&gt; function always starts a new REPL and automatically links the current buffer to it.&lt;/p&gt;
&lt;h3 id=&#34;improved-error-reporting&#34;&gt;Improved error reporting&lt;/h3&gt;
&lt;p&gt;The protocol changes how the errors are reported to the client, so the client could better analyze the stack traces and make them clickable.
Now, when the error occurs, a special buffer will pop up, displaying the detailed message and a clickable stack trace:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/error-buffer.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;The REPL itself shows a shortened message to avoid too much visual noise.&lt;/p&gt;
&lt;h3 id=&#34;improved-xref-eldoc-and-completion-at-point-support&#34;&gt;Improved Xref, Eldoc, and completion-at-point support&lt;/h3&gt;
&lt;p&gt;Fennel REPL has a command that can provide you with the target file and line of the definition you&amp;rsquo;re interested in, but it&amp;rsquo;s a bit tedious to copy it from the REPL every time.
So the new Xref integration uses a special protocol OP that will automate most of the things.&lt;/p&gt;
&lt;p&gt;Eldoc support was already part of the &lt;code&gt;fennel-mode&lt;/code&gt;, but it was implemented poorly.
The new implementation is asynchronous, and should never block Emacs if the REPL is busy, like what&amp;rsquo;s happened with an older implementation.
We will remove eldoc support from basic &lt;code&gt;fennel-repl&lt;/code&gt; in the future as it causes lots of problems.
Unfortunately, asynchronous Eldoc is a feature of Emacs 28+.
I&amp;rsquo;ve decided not to implement support for older versions of Emacs because in the case of Fennel, there&amp;rsquo;s no way of querying for documentation concurrently with the currently running task, like can be done in other languages, and blocking Emacs is not fun.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/arglist-hint.png&#34;
         alt=&#34;Figure 1: Argument list hint by Eldoc&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Argument list hint by Eldoc&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/eldoc.png&#34;
         alt=&#34;Figure 2: Documentation hint by Eldoc&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Documentation hint by Eldoc&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Completion at point also received some enhancements and should be much faster now, because everything is now processed in batches.
The previous implementation requested a list of completions with one command and then sent a request for each item to get its kind.
The new implementation does an initial request, and then a second request that gets kinds for all results of previous requests and caches them until the next completion happens.&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-04-08-new-fennel-proto-repl-and-call-for-testing/completion.png&#34;
         alt=&#34;Figure 3: Completions, complete with candidate kinds, and documentation&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Completions, complete with candidate kinds, and documentation&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Overall, all these features should be more robust, because we no longer require parsing the output of the REPL, as we had to with comint.&lt;/p&gt;
&lt;h2 id=&#34;rough-edges&#34;&gt;Rough edges&lt;/h2&gt;
&lt;p&gt;The implementation is not perfect, so there are some things to be concerned about.&lt;/p&gt;
&lt;p&gt;The client code is still can be improved performance-wise.
Nothing crazy, but if the process starts spitting out lots of output, it can start piling up and Emacs will chug on it.
This happens when printing huge tables, like &lt;code&gt;_G&lt;/code&gt;, or when a tight loop produces a lot of output, like &lt;code&gt;(for [i 1 1000000] (print i))&lt;/code&gt;.
Disabling process logging can help, and this is why the logging is disabled by default.
Though it should not be a major problem because large amounts of output are rare, and data is usually small.&lt;/p&gt;
&lt;p&gt;The buffer linking mechanism is not as user-friendly as something more automatic, like linking REPLs based on project structure, I agree.
But I hope it is not as bad, and we can always improve this part later as we gather more feedback from the users.&lt;/p&gt;
&lt;p&gt;Lastly, the overall complexity of the client may seem daunting, and there&amp;rsquo;s a lot of code but the architecture is quite simple, it&amp;rsquo;s just that there&amp;rsquo;s a lot of code for various features.&lt;/p&gt;
&lt;p&gt;I hope that it will be good enough to be the default REPL one day.
However, as I&amp;rsquo;ve mentioned, there may be problems with embedded REPLs or just the fact that you can&amp;rsquo;t update the old Fennel version due to some circumstances.
For these cases, there&amp;rsquo;s always the old implementation of the REPL.&lt;/p&gt;
&lt;h2 id=&#34;the-protocol-library&#34;&gt;The Protocol library&lt;/h2&gt;
&lt;p&gt;The protocol behind the new client is in fact editor-agnostic and can be used by other editors.
Because of that, I&amp;rsquo;ve released the protocol as a library: &lt;a href=&#34;https://github.com/andreyorst/fennel-proto-repl-protocol&#34; target=&#34;_blank&#34;&gt;fennel-proto-repl-protocol&lt;/a&gt;, and I&amp;rsquo;m looking forward to others trying it and implement support in their editors.&lt;/p&gt;
&lt;p&gt;The protocol setup is quite simple - all you have to do is either require the protocol library from the REPL and call the provided function with an editor-specific format function.
Or you can send the whole protocol code to a running REPL without using &lt;code&gt;require&lt;/code&gt; as the &lt;code&gt;fennel-proto-repl&lt;/code&gt; module does.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example for JSON based messaging:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-json&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{%s}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:sym&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.protocol.internal-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wrong data kind&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:gsub&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\\\\n&amp;#34;&lt;/span&gt;))) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;function&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x563fec938af0&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:protocol&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-json&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;0&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;op&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;0.1.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;1.3.1-dev&amp;#34;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lua&amp;#34;&lt;/span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;PUC Lua 5.4&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more info, see the project&amp;rsquo;s &lt;a href=&#34;https://github.com/andreyorst/fennel-proto-repl-protocol/blob/4d4e447094252746e2f0258f075c2d7f95fafa8d/README.md&#34; target=&#34;_blank&#34;&gt;readme&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All in all, I hope this will help make better tooling for Fennel in the future, and will bring the programming experience closer to what&amp;rsquo;s available for other Lisps.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Comint is the generic mechanism for implementing &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Shell-Mode.html&#34; target=&#34;_blank&#34;&gt;interactive shells&lt;/a&gt; in Emacs.
It works by setting up a process output filter and convenience functions for sending input to the process, but it&amp;rsquo;s hard to use it as a machine-to-machine interface.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: New Fennel Proto REPL and call for testing&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 08 Apr 2023 10:25:00 +0300</pubDate>
    </item><item>
      <title>Implementing a protocol-based Fennel REPL and Emacs client</title>
      <link>https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/</link>
      <guid>https://andreyor.st/posts/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/</guid>
      <description>&lt;p&gt;Recently I read a post by &lt;a href=&#34;https://tonsky.me/&#34; target=&#34;_blank&#34;&gt;@nikitonsky&lt;/a&gt; about &lt;a href=&#34;https://tonsky.me/blog/clojure-sublimed-3/&#34; target=&#34;_blank&#34;&gt;writing a custom REPL for Clojure and Sublime Text&lt;/a&gt;.
What got my attention was a way of implementing a protocol over a plain Clojure REPL.
In the post, Nikita describes a way to &lt;a href=&#34;https://tonsky.me/blog/clojure-sublimed-3/#repl-upgraded&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;upgrade&amp;rdquo; the connection&lt;/a&gt; by sending code that basically implements a new REPL to the main REPL process.
I liked the idea and decided that two can play this game, and started working on a similar thing, but for Fennel.&lt;/p&gt;
&lt;p&gt;A few months ago I&amp;rsquo;ve &lt;a href=&#34;https://lists.sr.ht/~technomancy/fennel/%3C87o7uuw4sj.fsf%40gmail.com%3E&#34; target=&#34;_blank&#34;&gt;already proposed&lt;/a&gt; the idea of a simple protocol for the Fennel REPL.
The idea was met with a certain amount of skepticism because there&amp;rsquo;s already an implementation of a such protocol that is language agnostic (in theory) and battle-tested.
The protocol in question is called &lt;a href=&#34;https://nrepl.org/&#34; target=&#34;_blank&#34;&gt;nREPL&lt;/a&gt; and it is widely used in the Clojure ecosystem.
There are several client implementations for various editors, and the protocol is extensible enough to support other languages and various clients.&lt;/p&gt;
&lt;p&gt;In fact, Fennel already has an implementation of the nREPL protocol, called &lt;a href=&#34;https://gitlab.com/technomancy/jeejah&#34; target=&#34;_blank&#34;&gt;jeejah&lt;/a&gt;.
However, it has problems.&lt;/p&gt;
&lt;p&gt;First of all, nREPL is mainly designed for Clojure, tested against Clojure, and implements features that Clojure needs in a pretty specific Clojure way.
It&amp;rsquo;s not impossible to implement support for other languages, and there &lt;a href=&#34;https://nrepl.org/nrepl/beyond_clojure.html&#34; target=&#34;_blank&#34;&gt;were attempts&lt;/a&gt; of various completeness.&lt;/p&gt;
&lt;p&gt;Another problem is that nREPL has &amp;ldquo;n&amp;rdquo; in its name for a reason.
It&amp;rsquo;s a Network REPL, which means that the protocol is designed around network communication pipelines.
In principle, it is possible to implement a standard-input/-output or a pipe-based version, but no clients will probably support it.
And Fennel, running on Lua, has some problems with networking.
The luasocket library becomes a dependency and there&amp;rsquo;s no clear way of implementing asynchronous communication.
Again, not impossible, JeeJah does it, but it&amp;rsquo;s hard to do it properly.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also bencode.
It&amp;rsquo;s an encoding that is used by torrents.
Encoding and decoding messages may be slow, especially in a single-threaded REPL.
And we&amp;rsquo;ll need to re-implement half of &lt;code&gt;fennel.view&lt;/code&gt; the serialization function to support all kinds of Lua quirks.&lt;/p&gt;
&lt;p&gt;Nikita also has some thoughts on nREPL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You need to add nREPL server dependency to your app. It also has a noticeable startup cost (~500ms on my machine).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which is a good point, although it&amp;rsquo;s not completely true.
Some existing nREPL clients, such as CIDER, can inject the nREPL dependency into your project, so you don&amp;rsquo;t need to actually ship it with your application.
You develop with nREPL, and use all of its goodies, yet your app has no nREPL once it&amp;rsquo;s shipped.
So you only need to include the nREPL dependency if you want to ship your application with capabilities for remote code execution.&lt;/p&gt;
&lt;p&gt;This is not really possible with Fennel, however.
There&amp;rsquo;s no package manager for fennel, and neither there is a way to dynamically inject an entire nREPL library from the client.
But what about injecting a smaller and simpler protocol?&lt;/p&gt;
&lt;p&gt;Why, yes!
That&amp;rsquo;s exactly what Nikita is doing in their Clojure-Sublimed plugin, and I&amp;rsquo;ve decided to do the same in Emacs.&lt;/p&gt;
&lt;h2 id=&#34;the-protocol&#34;&gt;The protocol&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve read the mailing list discussion I linked earlier, you&amp;rsquo;ve seen that I envisioned line-based, tab-separated messages.
I&amp;rsquo;ve scraped the idea and went for data-based communication: table in, plist out.
Tables can be interpreted by fennel, we can pattern-match on them, and store arbitrary amounts of data.
Plists are natively understood by Emacs Lisp, which is an implementation language of our client.&lt;/p&gt;
&lt;p&gt;So my idea was that I send something like that to Fennel REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(+ 1 2 3)&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And get back something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lisp&#34; data-lang=&#34;lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;accepted&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;6&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll explain why there are three outgoing messages for one incoming, but a bit later.
Right now we need to address the main problem: how do we teach Fennel to work in terms of our protocol?&lt;/p&gt;
&lt;p&gt;When I thought about the protocol for the first time, I thought that it will be part of the Fennel REPL by default.
However, Fennel is quite minimalist, and the choice was not to include anything like that.
The REPL is already better than the Lua one.
This is true when we&amp;rsquo;re talking about interactive usage, but not when we&amp;rsquo;re talking about machine interaction.&lt;/p&gt;
&lt;p&gt;So the answer is - REPL upgrade.&lt;/p&gt;
&lt;h2 id=&#34;upgrading-the-repl&#34;&gt;Upgrading the REPL&lt;/h2&gt;
&lt;p&gt;This technique is using the ability to evaluate in the existing REPL, basically implementing a different REPL at runtime.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s the simplest REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.eval&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sending it to Fennel REPL starts our own REPL inside of it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Welcome to Fennel 1.3.0 on PUC Lua 5.4!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Use ,help to see available commands.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Try installing readline via luarocks for a better repl experience.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (let [fennel (require :fennel)] (while true (io.write &amp;#34;repl&amp;gt;&amp;gt; &amp;#34;) (io.flush) (print (fennel.eval (io.read)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl&amp;gt;&amp;gt; (+ 1 2 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, it&amp;rsquo;s more of a downgrade, rather than an upgrade.
Our prompt doesn&amp;rsquo;t support unfinished expressions, comma-commands no longer work, and so on.
The purpose of this example is to give you a general idea of how the upgrade process works.&lt;/p&gt;
&lt;p&gt;Reimplementing the REPL from scratch is a tough task, but we don&amp;rsquo;t even have to do it!
Fennel comes with an extensible REPL already: the &lt;code&gt;fennel.repl&lt;/code&gt; function accepts a table with the following callbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;readChunk&lt;/code&gt; - poll for the user input.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onValues&lt;/code&gt; - called when the REPL returns the result of the evaluation,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onError&lt;/code&gt; - called when the error occurs,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pp&lt;/code&gt; - pretty-printer function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we implement these functions we&amp;rsquo;ll get a REPL that works the way we need it to.&lt;/p&gt;
&lt;h3 id=&#34;implementing-the-proto--col-type--repl&#34;&gt;Implementing the Proto(col|type) REPL&lt;/h3&gt;
&lt;p&gt;First things first, we need &lt;code&gt;fennel&lt;/code&gt; the library.
We&amp;rsquo;ll use some of its public API, later on, but the feature we&amp;rsquo;re interested in the most right now is &lt;code&gt;fennel.repl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m caching &lt;code&gt;fennel&lt;/code&gt; and &lt;code&gt;io&lt;/code&gt; functions to avoid some repeated table lookups.
It&amp;rsquo;s only part of the reason though, but more on that later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 0] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-values&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll go through the implementation of each callback but I will not implement the whole protocol as part of this post.
The protocol while small, still has a lot of code, so I&amp;rsquo;ll only do parts that pose interesting challenges.
It will still be a functional protocol, just not as feature-full as the one I&amp;rsquo;ve actually implemented for Emacs integration.&lt;/p&gt;
&lt;p&gt;First things first, let&amp;rsquo;s make the &lt;code&gt;read-chunk&lt;/code&gt; callback.
In the built-in REPL, it is used to print the prompt and handle user input.
We don&amp;rsquo;t need the prompt, as this will not be an interactive REPL, but we do need to poll for user input.
Not just that, our input comes in a form of a message, so we also need to parse it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser-state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message did not conform to protocol&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed input: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;read-chunk&lt;/code&gt; function we&amp;rsquo;re reading a line from the client and &lt;code&gt;eval&lt;/code&gt; it.
I could have used just the parser here, but you&amp;rsquo;ll see why having &lt;code&gt;eval&lt;/code&gt; here is useful.
If the evaluation was successful, we call &lt;code&gt;case&lt;/code&gt; and do pattern matching on the message.
If the message matches any pattern (right now the only one) we know how to process it.
The processing is handled by the &lt;code&gt;accept&lt;/code&gt; function, so let&amp;rsquo;s implement it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; -1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;unsupported op: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code is quite simple.
The &lt;code&gt;message&lt;/code&gt; function is what sends a message &lt;code&gt;(:id 1 :op &amp;quot;accepted&amp;quot;)&lt;/code&gt; to the client.
Here&amp;rsquo;s how we implement it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.format&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.format&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kvs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:%s %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:format&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;message&lt;/code&gt; function simply prints messages to standard out, while &lt;code&gt;format&lt;/code&gt; handles transforming our sequence of pairs to Emacs Lisp plist.&lt;/p&gt;
&lt;p&gt;Believe it or not, we&amp;rsquo;re almost done.
What&amp;rsquo;s left are &lt;code&gt;on-values&lt;/code&gt; and &lt;code&gt;on-error&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-values&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.done&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.data&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:values&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-error&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.done&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.error&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;done&lt;/code&gt; function is the final piece of the puzzle:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.done&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With all of this, we should get our protocol-based REPL up and running after calling &lt;code&gt;(proto-repl)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (proto-repl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 0 :op &amp;#34;init&amp;#34; :data &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(+ 1 2 3)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;6&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nice!
Now, obviously, this omits a lot of plumbing, error handling, other operations, and so forth, but it should give you the idea.
Also, there are a lot of unnecessary table lookups, I just wrote the code in such a way so you could evaluate them one after another without forward declarations.
But, as a result, sending each of those code blocks to a plain Fennel REPL gives us a new REPL that acts in terms of a specified protocol.
Now we&amp;rsquo;ve really upgraded the REPL.&lt;/p&gt;
&lt;p&gt;Unfortunately, this will not work as is, not because we&amp;rsquo;re missing ops or error handling though.
There&amp;rsquo;s an elephant in the room, consider this message: &lt;code&gt;{:id 1 :eval &amp;quot;(print :foo)&amp;quot;}&lt;/code&gt;.
What would happen if we send this message to our REPL?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.write :foo)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;#&amp;lt;file (0x7feff913f780)&amp;gt;&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Right, the output is mixed with the protocol messages.
Here&amp;rsquo;s another one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.read :l)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now our REPL suddenly waits for user input midway.
So if another protocol message comes, it will be consumed by this read.
So we have to handle this too.&lt;/p&gt;
&lt;h4 id=&#34;handling-io&#34;&gt;Handling IO&lt;/h4&gt;
&lt;p&gt;Unfortunately, Lua doesn&amp;rsquo;t have any way of redirecting output from standard out to something else.
Clojure kinda does:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;with-out-str&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.println&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;System/out&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even though we call the &lt;code&gt;println&lt;/code&gt; method of the &lt;code&gt;System/out&lt;/code&gt; class, this expression still returns a string &lt;code&gt;&amp;quot;foo\n&amp;quot;&lt;/code&gt;.
It is possible because in the JVM there are ways to configure that.
I&amp;rsquo;ve tried using &lt;code&gt;io.output&lt;/code&gt; in Fennel, but it can only be set to a file, we can&amp;rsquo;t pass it a table that implements the necessary methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; naive approach&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.output&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fake-file&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t.data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t.data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.output &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fake-file&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; runtime error: bad argument #1 to &amp;#39;output&amp;#39; (FILE* expected, got table)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.output &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;orig-out&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fake-file.data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we need to set up IO in such a way that it works as expected when we communicate through a protocol, yet wraps the IO inside of the user&amp;rsquo;s code.
Fortunately, we can do that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-io&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stderr&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdout&lt;/span&gt;} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt;} (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:__index&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.print&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.write&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.write&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.output&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.input&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd.write&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdout&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stderr&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;print&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/write&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd.read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stdin&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;env.io.read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit of code, but what it essentially does is this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;store the original values of &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;stderr&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;define a bunch of replacement functions, like &lt;code&gt;env.print&lt;/code&gt;, &lt;code&gt;env.io.write&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;capture original &lt;code&gt;*FILE&lt;/code&gt; metatable in &lt;code&gt;fd&lt;/code&gt; and override it&amp;rsquo;s metamethods.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlike tables, all file objects in Lua share the same metatable, so we only need to redefine metatable entries for the &lt;code&gt;stdin&lt;/code&gt; file.
Though it may depend on the implementation of the Lua runtime being used.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;env&lt;/code&gt; argument here is a table that will be used in the &lt;code&gt;fennel.repl&lt;/code&gt;, so we need to change that bit of code.
Because we don&amp;rsquo;t want to actually modify the real &lt;code&gt;_G&lt;/code&gt; table, we&amp;rsquo;ll need to copy it first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;copy-table&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;collect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s our new REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 0] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:env&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;doto &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;copy-table&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-io&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-values&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.on-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pp&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, when we send the &lt;code&gt;{:id 1 :eval &amp;quot;(io.write :foo)&amp;quot;}&lt;/code&gt; message, we get proper IO handling:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; (proto-repl)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 0 :op &amp;#34;init&amp;#34; :data &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.write :foo)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;print&amp;#34; :data &amp;#34;foo&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;#&amp;lt;file (0x7f0e234e7780)&amp;gt;&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Great, now we get a message with the &lt;code&gt;print&lt;/code&gt; OP, and the data to be printed.
The client then can detect such message and act accordingly.
We can even add support for different descriptors, hide &lt;code&gt;stderr&lt;/code&gt; messages, or color them differently.
But what about the opposite operation?
How do we read input from the user?&lt;/p&gt;
&lt;p&gt;This is a bit tricky.
The general idea is the same, we need to tell the client that the REPL is awaiting input, but we also need to wait in such way that other messages don&amp;rsquo;t get confused with user input.
You can see that in the &lt;code&gt;set-io&lt;/code&gt; function, the &lt;code&gt;io.read&lt;/code&gt; calls &lt;code&gt;protocol.read&lt;/code&gt; if the descriptor is &lt;code&gt;stdin&lt;/code&gt;.
Let&amp;rsquo;s implement &lt;code&gt;protocol.read&lt;/code&gt; now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;mktemp -u /tmp/proto-repl.XXXXXXXX 2&amp;gt;/dev/null&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;mkfifo &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#39; 2&amp;gt;/dev/null&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.message&lt;/span&gt;  [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.current-id&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:op&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;read&amp;#34;&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;with-open &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.open &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.popen &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;rm -f &amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tmpname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we call &lt;code&gt;io.read&lt;/code&gt; as part of our code, we should get back a message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(io.read :n)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;accept&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;read&amp;#34; :data &amp;#34;/tmp/proto-repl.adTbqVI2&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we write data, in this case a number to that file, we should get it processed by the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;echo&lt;/span&gt; 27 &amp;gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/tmp/proto-repl.adTbqVI2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And indeed we get the usual messages we get from &lt;code&gt;eval&lt;/code&gt; OP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;eval&amp;#34; :values (&amp;#34;27&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(:id 1 :op &amp;#34;done&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, Lua doesn&amp;rsquo;t have an inbuilt filesystem library, so this method is not cross-platform.
It will probably work under BSD systems, and Macs, but not under Windows, unless you&amp;rsquo;re using WSL, but still not guaranteed.
I don&amp;rsquo;t have a Windows PC, so I can&amp;rsquo;t test, but if you know a cross-platform, or even just a special case for Windows, for creating a named FIFO pipe, and attaching to it, it&amp;rsquo;d be great if you reach me.&lt;/p&gt;
&lt;p&gt;This pretty much concludes our very basic, yet fully functional protocol!&lt;/p&gt;
&lt;p&gt;The IO part is the trickiest part because there may be specifics to how files are read, but again, we can&amp;rsquo;t expect that the target application will have &lt;code&gt;luafilesystem&lt;/code&gt; installed.
But there&amp;rsquo;s a way to work this around.
So we do have a final small change to make in our &lt;code&gt;read-chunk&lt;/code&gt; function.&lt;/p&gt;
&lt;h4 id=&#34;making-the-protocol-extensible-at-runtime&#34;&gt;Making the protocol extensible at runtime&lt;/h4&gt;
&lt;p&gt;You may remember that I&amp;rsquo;ve chosen &lt;code&gt;eval&lt;/code&gt; over &lt;code&gt;parser&lt;/code&gt; in the REPL to work with incoming messages.
There was a specific reason for it - the message can actually be not for the target application, but for the REPL itself!
And we don&amp;rsquo;t even need any kind of special-casing for it, only a &lt;code&gt;nop&lt;/code&gt; OP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser-state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/write&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message did not conform to protocol&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed input: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We also need to expose the &lt;code&gt;protocol&lt;/code&gt; table in the &lt;code&gt;_G&lt;/code&gt; table, and &lt;code&gt;fennel&lt;/code&gt; for convenience:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.proto-repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.fennel&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these changes, we can send a message like &lt;code&gt;(do (print &amp;quot;hi!&amp;quot;) {:id 1 :nop &amp;quot;&amp;quot;})&lt;/code&gt; and it will be processed by the &lt;code&gt;eval&lt;/code&gt;, and the &lt;code&gt;print&lt;/code&gt; call will be evaluated outside of the main protocol handling.
Thus, we can get fancy!
Here, for example, how we can make our protocol respond in JSON:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-json-protocol&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_G.proto-repl.format&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;table.concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;icollect &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:table&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;type &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.view&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:id&lt;/span&gt; 15 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we send this to the REPL, we will get nothing back, since the OP in question is &lt;code&gt;nop&lt;/code&gt;, however, the &lt;code&gt;format&lt;/code&gt; function will be redefined.
So if we send one more message, the usual &lt;code&gt;eval&lt;/code&gt; one, we&amp;rsquo;ll get back JSON messages in response:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt; {:id 1 :eval &amp;#34;(+ 1 2 3)&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;id&amp;#34;: 1, &amp;#34;op&amp;#34;: &amp;#34;accept&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;id&amp;#34;: 1, &amp;#34;op&amp;#34;: &amp;#34;values&amp;#34;, &amp;#34;data&amp;#34;: [&amp;#34;6&amp;#34;]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;id&amp;#34;: 1, &amp;#34;op&amp;#34;: &amp;#34;done&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is why languages with the capability to run any code at runtime are cool in my opinion.
We can build our application while it is running.
Any protocol method, that we&amp;rsquo;ve defined can be re-implemented at runtime.
So if you&amp;rsquo;re running Windows, you can redefine &lt;code&gt;protocol.read&lt;/code&gt; to support your particular platform without even asking me to update the code.
(But please, if you know a more portable way of handling input, send me a message).&lt;/p&gt;
&lt;p&gt;As a final change, let&amp;rsquo;s remove the &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; prompt from the &lt;code&gt;read-chunk&lt;/code&gt;, and we&amp;rsquo;re done.
The prompt is not needed, it was only to help you differentiate what messages we&amp;rsquo;ve sent, and what messages we receive.
For the machine the prompt will only get in the way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.read-chunk&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parser-state&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io/read&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:l&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcall &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ok?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;protocol.accept&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:nop&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;} &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;message did not conform to protocol&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;error &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;malformed input: &amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can add the call to &lt;code&gt;proto-repl&lt;/code&gt; to our protocol code, so right after we&amp;rsquo;ve sent it the new REPL is started automatically:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, for real, this concludes the basic protocol implementation.
This is, in fact, what I started with, and then gradually made it more mature by extending the number of operations the protocol supports, and making it more robust.
Not every protocol method is exposed to be changed in my implementation though.
This was more like a demo that you can follow, but in the real version of the protocol, it is a single giant function that gets sent to the REPL in one go.&lt;/p&gt;
&lt;p&gt;Now, we can talk about the client, because without the client our protocol has no value.&lt;/p&gt;
&lt;h2 id=&#34;the-client&#34;&gt;The client&lt;/h2&gt;
&lt;p&gt;My editor of choice is Emacs for many reasons.
And this is one of them - we can make all kinds of applications in Emacs, including a custom client for a custom protocol.
We&amp;rsquo;re like full-stack developers now, but our backend is written in Fennel and our frontend will be written in Emacs Lisp.&lt;/p&gt;
&lt;p&gt;As I mentioned at the beginning of the post, I&amp;rsquo;ve chosen plists because Emacs understands them natively.
Still, our messages come in as strings, so we&amp;rsquo;ll need to parse them.
But how will we organize our client to begin with?&lt;/p&gt;
&lt;h3 id=&#34;comint&#34;&gt;Comint&lt;/h3&gt;
&lt;p&gt;The current implementation of the Fennel REPL in the &lt;code&gt;fennel-mode&lt;/code&gt; package uses the inbuilt &lt;code&gt;comint&lt;/code&gt; package to do all of the heavy lifting.
Comint is Emacs&amp;rsquo; generic interface for providing user interaction to asynchronous processes.
The selling point is that you can start almost any interactive program in Comint, set the prompt regexp and it will work.
However, the problems start when we begin building a machine-to-machine interface over a human-to-machine interface.&lt;/p&gt;
&lt;p&gt;As with any kind of interface it involves parsing the output.
Our protocol is no different here, we&amp;rsquo;re still going to parse output, so what&amp;rsquo;s wrong with doing it via comint, especially since it already knows how to do the majority of things?
Comint even has the redirection facility to deal with such tasks specifically.&lt;/p&gt;
&lt;p&gt;The answer is - there&amp;rsquo;s no message queue that spans over both comint and the target process.&lt;/p&gt;
&lt;p&gt;For example, you can send a long-running code to the REPL that will print something after a long period of time, like this one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1 1000000] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;baz&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the loop is completed the stdout of the process will contain a string like this one: &lt;code&gt;foo\tbar\tbaz&lt;/code&gt;.
Comint will grab it and print it to the REPL.
All good.&lt;/p&gt;
&lt;p&gt;But if we set up a redirect while this loop runs, that, say, queries for the completions from the REPL, we can get into a funny situation.
Imagine, user typed &lt;code&gt;f&lt;/code&gt; and pressed the &lt;kbd&gt;Tab&lt;/kbd&gt; key.
The current implementation of completion support in &lt;code&gt;fennel-mode&lt;/code&gt; package will use a comint redirect mechanism, and for this case, it will send the following expression &lt;code&gt;,complete f&lt;/code&gt; to the REPL.
The output of the &lt;code&gt;,complete f&lt;/code&gt; command will be &lt;code&gt;fn\tfor\tfcollect\tfaccumulate&lt;/code&gt;, another tab-separated line, but our REPL is busy at the moment, running the loop.
What can go wrong?&lt;/p&gt;
&lt;p&gt;What happens is that the &lt;code&gt;,complete f&lt;/code&gt; is buffered by the process stdin, and not processed unless the REPL is able to read the message.
The comint redirect, however, is waiting for the output from the process and grabs what&amp;rsquo;s first to appear there.
So it grabs the output from the &lt;code&gt;print&lt;/code&gt; function and uses it as the data for the completion engine.
While the REPL gets the output from the &lt;code&gt;,complete&lt;/code&gt; command:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/redirection-race.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This is a race, and the last request from comint wins the first output from the process.
It just so happens that both messages used a format similar enough for completion to work.
In most cases, completion will silently fail, and the REPL will just lose the results of the expression.&lt;/p&gt;
&lt;p&gt;Comint is not suited for working with a protocol like ours, but we can still reuse a fair bit of comint features in our client.
Instead, we&amp;rsquo;ll have two separate processes - one for the server that implements the protocol, and one for the REPL that acts as a fake process with all comint goodies.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what our architecture will look like:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/scheme.svg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;By separating input from output, and effects from parsing, we avoid all problems with comint racing over process output and misparsing different commands.
And the input doesn&amp;rsquo;t have to come from comint, we can send messages via the input sender from anywhere, so code interaction in the buffer is easy to implement too.&lt;/p&gt;
&lt;p&gt;Notice how ID comes into play here - we read user input, format it as a message, and assign it an ID, which we send to the server.
While doing so, we register a callback for the message in a hash table, that uses message IDs as keys, and callback as values.
Once the server has processed the message, it responds with several messages of its own, all of which include a callback.
We then parse these messages in the output filter, which looks for the callback in the hash table.
If the callback was found, it is being called with the data from the message according to the protocol.
And the callback can print the result back to the REPL, to a completion engine, or to any other target buffer.&lt;/p&gt;
&lt;p&gt;This is also the reason why our protocol answers with special messages &lt;code&gt;accept&lt;/code&gt; and &lt;code&gt;done&lt;/code&gt; before and after the data-oriented ones, like &lt;code&gt;values&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, and such.
All protocol operations require a callback to reach the user, but once the message is processed fully its callback can be released.
This is what the &lt;code&gt;done&lt;/code&gt; OP is for in our protocol, but what about &lt;code&gt;accept&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Right now in my design, &lt;code&gt;accept&lt;/code&gt; is a noop, but I can see some potential later use cases.
One of them is for implementing asynchronous timeouts.
For example, when we register a callback we can store the maximum amount of time that is meaningful for such a callback to exist.
Once the server answers with the &lt;code&gt;accepted&lt;/code&gt; OP, we can check if the time since callback registration exceeds the lifespan of the callback.
If not, we continue waiting for other messages, otherwise, we unassign it.&lt;/p&gt;
&lt;p&gt;Another possible use for the  &lt;code&gt;accept&lt;/code&gt; OP is to cancel previous callbacks.
This is not particularly useful in the context of a single-threaded Lua application, as it will always process messages sequentially, but nothing prevents us from implementing an asynchronous REPL.
In an asynchronous context, it is quite possible that a message will be accepted before the previous one was fully processed.
And in cases like when we query for completions, we are interested only in the latest results, so we can use &lt;code&gt;accept&lt;/code&gt; to cancel the previous completion callback.&lt;/p&gt;
&lt;p&gt;But enough talk, let&amp;rsquo;s write some code!&lt;/p&gt;
&lt;h3 id=&#34;server-process&#34;&gt;Server process&lt;/h3&gt;
&lt;p&gt;Now, I must say, that in the same way that we didn&amp;rsquo;t implement a full-blown protocol, we won&amp;rsquo;t implement a full-blown client.
However, I will try to provide a complete enough example that you&amp;rsquo;ll be able to make your own client like this in the future if you wanted to.&lt;/p&gt;
&lt;p&gt;We start simple - we need a way to start the server process that will act as a pipe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--upgrade-code&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...whole protocol code...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; *proto-repl*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-server&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Start the Fennel REPL process.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;COMMAND is used to start the Fennel REPL.  Sends the upgrade code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;to the REPL and waits for completion via a callback.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:command&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;split-string-shell-command&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:connection-type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;pipe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--process-filter&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-disable-undo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode-line-process&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:%s&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Waiting for Fennel REPL initialization...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--assign-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--upgrade-code&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First of all, let&amp;rsquo;s address the elephant in the room - the protocol code.
Our package needs to somehow obtain the protocol code and send it to the REPL process.
I&amp;rsquo;ve chosen to store it as a string, even though it is a very long string.
The reasoning behind this is that I want this file to be both self-contained and because package management in Emacs is a mess, and there&amp;rsquo;s no reliable way to obtain a file that is located in the same package unless they&amp;rsquo;re both in the same directory, which may not be the case&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
Not the most elegant solution, but it works.&lt;/p&gt;
&lt;p&gt;Next up, we define two more variables, one for process buffer name, and another one for storing callbacks.
For simplicity&amp;rsquo;s sake, I&amp;rsquo;ll use an associative list for callbacks, but in the real client, a hash table with fast equality function should be used.&lt;/p&gt;
&lt;p&gt;And the main piece of code - the function that starts the process.
Code should be mostly self-explanatory, but in case it&amp;rsquo;s not, the main idea is to start the process and assign a process filter to it.
The process filter will be the next thing we&amp;rsquo;ll implement, so I&amp;rsquo;ll save the explanation for later.
After that, we do a few setup steps and send the message to the process with the upgrade code.
Sending messages is another bit part of the client, and we&amp;rsquo;ll look into them as well.&lt;/p&gt;
&lt;h4 id=&#34;process-filtering&#34;&gt;Process filtering&lt;/h4&gt;
&lt;p&gt;The process filter is a function that accepts two arguments, the process being filtered and the data that was read from it.
By specifying a custom process filter we actually prevent any output from the process in the process buffer, so some kind of logging should be implemented.
And here&amp;rsquo;s our first challenge.&lt;/p&gt;
&lt;p&gt;Our protocol works on a one message per line basis, yet the output from the process is received in hunks instead of lines.
It is quite possible to receive a message that contains the start of the next message without its end.
In a case like this, a custom encoding would be a much better choice than using a line-based protocol, but we can workaround the problem by implementing buffering.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--buffered-split-string&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Split STRING on newlines.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;If the string doesn&amp;#39;t end with a newline character, the last (or
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the only) line of the string is buffered and excluded from the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;result.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-lines&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setcar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-suffix-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-buf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;last&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nbutlast&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;strings&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we split the string on newlines, removing empty lines, as they&amp;rsquo;re irrelevant to us.
Next, if we have something in our buffer, we concatenate it with the first line, as it is a leftover from the previous hunk.
Then we check if the string ends with a newline, if it is we return lines as is.
If not, we set the buffer to the last incomplete line and return everything except for the last line.&lt;/p&gt;
&lt;p&gt;This way, the protocol is much more resilient to process buffering, and the fact that Emacs doesn&amp;rsquo;t read line by line on most systems.
Yes, our protocol is line-based and it&amp;rsquo;s not exactly machine-friendly, but it is much easier than using some kind of encoding, like bencode.&lt;/p&gt;
&lt;p&gt;Once we have a list of lines, we can begin processing them.
Here&amp;rsquo;s our process filter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--process-filter&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Parse the MESSAGE and process it with the callback handler.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--buffered-split-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(:id &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-from-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (error &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plistp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--handle-protocol-op&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-current-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-max&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this function, we&amp;rsquo;re going to work on a line-by-line basis because the first thing we do is split the incoming message.
However, the input massaging doesn&amp;rsquo;t stop there - for each message we want to strip everything that is not part of it.
If you remember, before we had our IO wrapped, the output from &lt;code&gt;io.write&lt;/code&gt; was right before one of the messages.
This is partly why we do it.
In fact, this should never happen, but we can&amp;rsquo;t control it before the protocol is initialized, especially because by default Fennel REPL is quite verbose.
If we send a partially complete expression to the base Fennel REPL it will display a &lt;code&gt;..&lt;/code&gt; prompt, so while sending our protocol line by line we&amp;rsquo;ll get back a lot of dots preceding the initialization message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...............................................(:id 0 :op &amp;#34;initialized&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we have to deal with it.
This function is also the right place to add logging, but I&amp;rsquo;m omitting it for the sake of simplicity and just emitting everything to the process buffer.&lt;/p&gt;
&lt;p&gt;After we&amp;rsquo;ve split the input, and truncated it we parse it with the &lt;code&gt;read-form-string&lt;/code&gt; function.
This again is where some errors might lurk - if our protocol ever would return two messages in a single line, we&amp;rsquo;ll lose the last one.
So you might want to check for that.
If the message was read successfully, we also check if it is a plist with the &lt;code&gt;plistp&lt;/code&gt; function, and pass it to the protocol handler.&lt;/p&gt;
&lt;p&gt;The protocol handler is the meat of our client.
It manages callbacks for each message and handles all supported protocol OPs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--handle-protocol-op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Handle protocol MESSAGE.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Message contains an id, operation to execute, and any additional
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;data related to the operation.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:op&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--get-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;op&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--unassign-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--callbacks-pending?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-prompt&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:values&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s\n&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-join&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;values&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;print&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--print&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:data&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;read&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inhibit-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;write-region&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;stdin: &amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:data&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:traceback&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;init&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--unassign-callback&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even though our protocol is quite small, we do have a few OPs to support.
As I&amp;rsquo;ve mentioned the &lt;code&gt;accept&lt;/code&gt; OP is a nop, but the &lt;code&gt;done&lt;/code&gt; OP is quite important.
You can see, that we unassign the callback for the message, and then check if there are pending callbacks.
This allows us to avoid drawing the prompt in the REPL because pending callbacks mean that the REPL is still busy.&lt;/p&gt;
&lt;p&gt;Another special OP is the &lt;code&gt;init&lt;/code&gt; one.
It has a special callback with the ID 0, and this callback is strictly for the REPL initialization.
Other callbacks should be pretty much self-explanatory.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s write functions for dealing with callbacks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--get-callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Get a callback for a message with this ID.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cdr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--unassign-callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Remove callback assigned to a message with this ID.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-delete-all&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--assign-callback&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Assign CALLBACK and return the id it was assigned to.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;proto-repl--message-callbacks&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;callback&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-id&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;1+&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--callbacks-pending?&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Check for callbacks that still waiting for the DONE message.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--message-callbacks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these, we can do all operations on callbacks that our client requires.
The &lt;code&gt;proto-repl--assign-callback&lt;/code&gt; is an interesting one.
It increments the ID after it assigned the callback, and returns the ID of the callback itself.
This is our main interface for sending messages to the REPL.&lt;/p&gt;
&lt;h4 id=&#34;user-interaction&#34;&gt;User interaction&lt;/h4&gt;
&lt;p&gt;With the server part mostly done, we can make the comint part that is an actual user interface to our protocol-based REPL.
Let&amp;rsquo;s start with the mode for the REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;fennel-mode&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; for font-lock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*Fennel Proto REPL*&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-derived-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fennel Proto REPL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Major mode for Fennel REPL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\\{proto-repl-mode-map}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-prompt-regexp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-prompt&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-prompt-read-only&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-input-sender&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;proto-repl--input-sender&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode-line-process&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;:%s&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comment-end&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-font-lock-setup&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-syntax-table&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-mode-syntax-table&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-check-proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;kill-buffer-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;delete-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;insert&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;;; Welcome to the Fennel Proto REPL\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set-marker&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-mark&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-prompt&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot to dig in, but the main part is where we start a new process with the &lt;code&gt;start-process&lt;/code&gt; function.
This process is what the comint will use for it&amp;rsquo;s internal implementation of input handling and such.
Let&amp;rsquo;s look at the &lt;code&gt;fennel-repl--input-sender&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--input-sender&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sender for INPUT from the REPL buffer to REPL process.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--assign-callback&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--print&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mesg&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{:id %s :%s %S}\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring-no-properties&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mesg&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is responsible for sending the input to the server as a message, so it formats user input like one.
Before sending the message it assigns the callback, and then the rest of our system should just work.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;proto-repl--display-prompt&lt;/code&gt; is a simple function that just prints the prompt to the REPL buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--display-prompt&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Display prompt.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-output-filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-prompt&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the &lt;code&gt;proto-repl--print&lt;/code&gt; is a default callback for printing anything to the REPL buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--print&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint-output-filter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is almost identical to the prompt displaying one, but it is mostly for the simplicity&amp;rsquo;s sake.
In fact the real one is a bit more complicated because we want to print stuff before the prompt if we&amp;rsquo;re sending code not from the REPL but from the buffer.
I&amp;rsquo;ve left this out as it&amp;rsquo;s not that hard to implement.&lt;/p&gt;
&lt;p&gt;So the last thing we need is to actually start the REPL in a buffer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-repl&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Start the REPL.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fennel Proto REPL initialized&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;with-current-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-create&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pop-to-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This one is a callback we&amp;rsquo;ve used when starting a server.
And this one is the funtion for the end user:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Fennel Proto REPL.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl-buffer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-live-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer-process&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pop-to-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repl-buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel --repl&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl--start-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel --repl&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proto-repl-buffer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the client is done!
Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client/new-client.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;On the left is the REPL buffer, which is responsible for input handling, and sending messages.
On the right is the server buffer, which shows the process log.
As you can see, we&amp;rsquo;ve got the usual messages for all our expressions.&lt;/p&gt;
&lt;h2 id=&#34;new-fennel-repl-integration-for-emacs&#34;&gt;New Fennel REPL integration for Emacs&lt;/h2&gt;
&lt;p&gt;Sure, the implementation of the client and the protocol has a lot of room for improvement, but it is enough for the purpose of this post.
As a matter of fact, I&amp;rsquo;m almost done working on a proper implementation, and most of the code here is greatly simplified version of what I&amp;rsquo;ve already made for the &lt;code&gt;fennel-mode&lt;/code&gt; package.
For now it lives in a separate module, but I have high hopes on completely replacing inbuilt comint-based client with this protocol based one, once I test it more.
It will probably still live in a separate module for a while even after I will consider it mostly complete, so users would be able to try it in their environments, but my hopes are high.&lt;/p&gt;
&lt;p&gt;There is one problem though - this protocol implementation may not work in some contexts.
For instance, if you&amp;rsquo;re already providing a custom REPL in your application, that is based on the &lt;code&gt;fennel.repl&lt;/code&gt; and implements its own &lt;code&gt;readChunk&lt;/code&gt;, that, for example, doesn&amp;rsquo;t read from &lt;code&gt;stdin&lt;/code&gt;.
One such example is the &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt; game engine, there&amp;rsquo;s an &lt;a href=&#34;https://gitlab.com/alexjgriffith/min-love2d-fennel/-/blob/master/lib/stdio.fnl&#34; target=&#34;_blank&#34;&gt;implementation&lt;/a&gt; of the REPL that polls for input on a separate thread.
If we send our protocol-based REPL to such a custom REPL, we&amp;rsquo;ll negate all the efforts made to make the REPL work in a non-blocking way.
For Clojure, this works because the REPL already lives in its own thread, but there are no threads in Lua apart from what coroutines provide.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m still thinking about how to handle the situation when the upgrade is impossible.
This is why the official protocol is much better than such a custom one, but alas.&lt;/p&gt;
&lt;p&gt;You can already try this REPL if you check out the &lt;code&gt;proto-repl&lt;/code&gt; branch in the &lt;a href=&#34;https://git.sr.ht/~technomancy/fennel-mode/tree/proto-repl&#34; target=&#34;_blank&#34;&gt;fennel-mode&lt;/a&gt; project.
If you&amp;rsquo;re using &lt;a href=&#34;https://github.com/radian-software/straight.el&#34; target=&#34;_blank&#34;&gt;straight.el&lt;/a&gt;, or &lt;a href=&#34;https://github.com/quelpa/quelpa&#34; target=&#34;_blank&#34;&gt;Quelpa&lt;/a&gt;, or Emacs version recent enough to have the &lt;code&gt;package-vc-install&lt;/code&gt; function, you can try installing fennel-mode and supplying the &lt;code&gt;proto-repl&lt;/code&gt; branch to the recipe.&lt;/p&gt;
&lt;p&gt;If you want to experiment with the code that is provided in this article for example for the purpose of building a similar protocol for another language, this very article is written in the literate style, and you can grab it &lt;a href=&#34;https://andreyor.st/2023-03-25-implementing-a-protocol-based-fennel-repl-and-emacs-client.org&#34;&gt;here&lt;/a&gt;.
Run the &lt;code&gt;org-babel-tangle&lt;/code&gt; on it, and you should get the &lt;code&gt;protocol.fnl&lt;/code&gt; file with all the necessary functions, and &lt;code&gt;proto-repl.el&lt;/code&gt; file with the Emacs Lisp code.
You&amp;rsquo;ll need to put the protocol code to the &lt;code&gt;proto-repl--upgrade-code&lt;/code&gt; variable, as I&amp;rsquo;ve excluded it from the article&amp;rsquo;s text since it was making that particular code block too long.&lt;/p&gt;
&lt;p&gt;Thank you for reading!
I hope this was interesting and useful.
As always, if you have any thoughts you want to discuss on the matter, feel free to contact me via one of the ways mentioned on the &lt;a href=&#34;https://andreyor.st/about#links&#34;&gt;about&lt;/a&gt; page.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Package managers like straight.el or quelpa use recipes to specify what files to use during the build process.
It is possible that users of the package may not notice that the recipe needs to be changed.
This can be handled by the package archive like MELPA, but I&amp;rsquo;d rather not bother with it right now.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Implementing a protocol-based Fennel REPL and Emacs client&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 25 Mar 2023 19:47:00 +0300</pubDate>
    </item><item>
      <title>Ad-hoc async in emacs-lisp via generators</title>
      <link>https://andreyor.st/posts/2023-02-01-ad-hoc-async-in-emacs-lisp-via-generators/</link>
      <guid>https://andreyor.st/posts/2023-02-01-ad-hoc-async-in-emacs-lisp-via-generators/</guid>
      <description>&lt;p&gt;TIL that Emacs Lisp has had generators since 2016, and generators are a cool feature in any language in my opinion!
In short, Emacs has the &lt;code&gt;generator.el&lt;/code&gt; package as it&amp;rsquo;s part since version 25.1.
The generators are implemented via transforming code and act like iterators, even most of the functions are called &lt;code&gt;iter-something&lt;/code&gt;.
Thus we can&amp;rsquo;t cross iterator boundaries without creating another iterator, so it&amp;rsquo;s not like they&amp;rsquo;re proper coroutines but we can still use them as such with these limitations in mind.&lt;/p&gt;
&lt;p&gt;As you may have noticed, &lt;a href=&#34;https://andreyor.st/posts/2023-01-09-comparison-of-manifold-and-clojurecoreasync/&#34;&gt;lately&lt;/a&gt; I &lt;a href=&#34;https://andreyor.st/posts/2022-12-09-fixed-version-of-pipeline-async-and-unordered-pipeline-variants/&#34;&gt;was&lt;/a&gt; &lt;a href=&#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/&#34;&gt;fiddling&lt;/a&gt; with Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; library, and implementation of a &lt;a href=&#34;https://andreyor.st/posts/2021-10-27-naive-async-implementation-in-fennel/&#34;&gt;similar concept&lt;/a&gt; for the Fennel language via &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-async&#34; target=&#34;_blank&#34;&gt;fennel-async&lt;/a&gt;.
Fennel, being a language that compiles to Lua, allows us to use Lua&amp;rsquo;s coroutines directly for implementing non-blocking operations on channels.
Clojure, on the other hand, doesn&amp;rsquo;t have proper coroutines, so to implement &lt;code&gt;core.async&lt;/code&gt; they transform the code into a state machine, which then gets executed on a thread pool.
Much like what &lt;code&gt;generator.el&lt;/code&gt; does!
Except for the thread pool part.&lt;/p&gt;
&lt;p&gt;I really like the concept of CSP (Communicating Sequential Processes) and when I learned that Emacs has generators I wanted to see if it is possible to implement something like &lt;code&gt;core.async&lt;/code&gt; in emacs-lisp.
Now, this isn&amp;rsquo;t like a proper implementation, but rather a simplified quick prototype of what can be done, and I know that there are a lot of other implementations, like &lt;a href=&#34;https://github.com/skeeto/emacs-aio&#34; target=&#34;_blank&#34;&gt;emacs-aio&lt;/a&gt; with is built on top of generators, but it uses promises instead of channels, and I like channels more.
I must say that I&amp;rsquo;m not great at writing Emacs Lisp code that mutates things, because I mostly try to write code in a functional style, to avoid errors that can be caused by mutation, but in this case mutation is the only way to achieve the desired result.&lt;/p&gt;
&lt;h2 id=&#34;layout&#34;&gt;Layout&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s describe the overall layout.
We will have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Channels - mutable places that store data in a sequential buffer;&lt;/li&gt;
&lt;li&gt;Primitives to create lightweight &lt;em&gt;threads&lt;/em&gt; that are executed by the scheduler;
&lt;ul&gt;
&lt;li&gt;Such threads are also channels.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Primitives to park threads when we do operations on channels.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s basically all we need to implement &lt;code&gt;core.async&lt;/code&gt;-style approach for writing code.&lt;/p&gt;
&lt;p&gt;Also, I should note that &lt;code&gt;generator.el&lt;/code&gt; requires &lt;code&gt;lexical-binding&lt;/code&gt; to be true, otherwise, it refuses to work, so before we begin, let&amp;rsquo;s set up it and require the library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;generator&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s start with channels.&lt;/p&gt;
&lt;h2 id=&#34;channel&#34;&gt;Channel&lt;/h2&gt;
&lt;p&gt;We start simple.
Let&amp;rsquo;s create a function that returns a new channel, with an optional size indication, that basically affects the buffering.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Create a channel with optional SIZE attribute.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (error &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;size must be greater than 0&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I know, I know.
This is definitively not a performant way of creating a queue, but it will do for our experiment purposes.
We can always remake this in a proper way later, and it with probably require very slight internal API changes.&lt;/p&gt;
&lt;p&gt;Next, we need a way to put items to the channel, take items off the channel, and close the channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan-status&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Return the status of the PORT or its size if any.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Put value VAL to the channel PORT.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;) (error &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;value can&amp;#39;t be nil&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan-status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;numberp&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;1+&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nconc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/take!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Take a value off the PORT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;last&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nbutlast&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Close the PORT.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setcar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:closed&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These functions never block.
If we can&amp;rsquo;t put value to the channel, we simply bail out and don&amp;rsquo;t do it.
If we can&amp;rsquo;t take value off the channel - again, we bail out.
So we can use these functions without ever worrying that they will block, but in reality, we shouldn&amp;rsquo;t because they don&amp;rsquo;t respect the fundamental parameter of a channel: backpressure.&lt;/p&gt;
&lt;p&gt;In reality, channels should have a separate queue of puts, a queue of takes, and an optional buffer, thus these functions should not drop any data, but to keep things simple, I&amp;rsquo;ve decided to only have the buffer.
We can fix this by introducing a few macros:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Parking take.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Takes a value off the PORT if it is not closed, and has something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;in the buffer.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;named-let&lt;/span&gt; ,&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; ((,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/take!&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond&lt;/span&gt; (,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:closed&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan-status&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-yield&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (,&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/take!&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Parking put.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Puts X onto the PORT if the port is not closed and has room in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the buffer.  X must not be NIL.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;) (,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;named-let&lt;/span&gt; ,&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; ((,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond&lt;/span&gt; (,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:closed&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan-status&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-yield&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (,&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why are these macros, you might ask?
Well, because we will be only using these in the generator context, and we can&amp;rsquo;t call &lt;code&gt;iter-yield&lt;/code&gt; from anywhere but the iterator&amp;rsquo;s body, in turn, we can&amp;rsquo;t make these two operations to be functions.
&lt;code&gt;Iter-yield&lt;/code&gt; is a transformation point for the iterator&amp;rsquo;s body, and thus it must be lexically present.
Now, let&amp;rsquo;s look at how we can use these.&lt;/p&gt;
&lt;p&gt;To test this out, we can create a channel and an iterator, which tries to take a value off the channel, and print it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  the channel with a buffer of 1
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;val: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  an iterator that uses our custom macro
&lt;/div&gt;
&lt;p&gt;Advancing the iterator does nothing, even if we call it multiple times, because &lt;code&gt;a/&amp;lt;!&lt;/code&gt; handles the wait:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-next&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; =&amp;gt; nothing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, if we put the value to the channel&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;and then advance the iterator&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-next&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;g&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;we&amp;rsquo;ll see the message &lt;code&gt;&amp;quot;val: 42&amp;quot;&lt;/code&gt; and receive the signal &lt;code&gt;iter-end-of-sequence&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, as you can see, the &lt;code&gt;g&lt;/code&gt; iterator parked itself at the &lt;code&gt;a/&amp;lt;!&lt;/code&gt; call, and the channel was acting as the synchronization point between the main process and our iterator.
Such an iterator really is like a lightweight thread, with cooperative scheduling, which we hid in the &lt;code&gt;a/&amp;lt;!&lt;/code&gt; macro.
However, manually advancing iterators isn&amp;rsquo;t great, so we can build a really simple scheduler that will do that for us.&lt;/p&gt;
&lt;h2 id=&#34;scheduler&#34;&gt;Scheduler&lt;/h2&gt;
&lt;p&gt;Our scheduler will use a simple list of processes and it will simply go through and execute each one after another.
Before we can write it though, we need a way to spawn our lightweight processes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/processes&lt;/span&gt; &amp;#39;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/spawn&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Start process F by supplying optional ARGS and &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`push&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; it to the task pool.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;apply&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/processes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-next&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can rewrite our previous example like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/spawn&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;val: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; 42))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But we still need to run the process and maintain its state, e.g. when the iterator is exhausted the process should be removed from the processes list.
This function takes care of this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/run&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Run each process in the task-pool, and remove those that have finished.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/processes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-next&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-end-of-sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/processes&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;delq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/processes&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/processes&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The return value of this function is either &lt;code&gt;t&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;, indicating whether there are processes left.
The simplest event loop is then can be defined like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/run&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, combined with the previous example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/spawn&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;val: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/run&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, this is the simplest scheduler possible, but we don&amp;rsquo;t care for now, as it is just a proof of concept.
There should be error handling, the ability to cancel processes, and ways to avoid running processes when they don&amp;rsquo;t want to be run, like when the process is sleeping.
A more sophisticated implementation can do all of this, but it&amp;rsquo;s a task for another day.&lt;/p&gt;
&lt;p&gt;Still, spawning tasks like this is not convenient enough, so we can create another macro to automate some stuff:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Create a lightweight thread that runs the BODY.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Thread is automatically parked when operations on channels occur.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;The return value itself is a channel.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;declare&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;indent&lt;/span&gt; 0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gensym&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    `(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;progn&lt;/span&gt; ,@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;body&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/spawn&lt;/span&gt; ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that it does a bit more than just wrapping &lt;code&gt;body&lt;/code&gt; into a &lt;code&gt;iter-lambda&lt;/code&gt;.
Instead, it also creates a channel, and splices in the &lt;code&gt;a/&amp;gt;!&lt;/code&gt; operation inside the &lt;code&gt;iter-lambda&lt;/code&gt; body.
This is done to make sure that we can await on the &lt;code&gt;a/go&lt;/code&gt; block on its own, using the same API as with channels, and actually get the result of the &lt;code&gt;body&lt;/code&gt;.
We can do so in a non-blocking way, by using one &lt;code&gt;a/go&lt;/code&gt; block inside another and awaiting the result via &lt;code&gt;a/&amp;lt;!&lt;/code&gt;, or we can define two blocking operations &lt;code&gt;a/&amp;lt;!!&lt;/code&gt; and &lt;code&gt;a/&amp;gt;!!&lt;/code&gt; to use from the main thread:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Blocking put.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Puts X onto the PORT if the port is not closed and has room in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;the buffer.  X must not be NIL.  If the buffer is full, block
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;until the buffer is ready to receive the value.  Should not be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;used inside the &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`a/go&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; blocks.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;named-let&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:closed&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan-status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/run&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Blocking take.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Takes a value off the PORT if it is not closed, and has something
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;in the buffer.  If the buffer is empty, will block until the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;buffer receives a value.  Should not be used inside the &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`a/go&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;blocks.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;named-let&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/take!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:closed&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan-status&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/run&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;loop&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/take!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, that we&amp;rsquo;re calling &lt;code&gt;a/run&lt;/code&gt; if the channel operation was not successful, either because it was full or empty, to allow other threads to advance and put or take data from it.
This allows us to avoid blocking indefinitely, and since we don&amp;rsquo;t have a thread pool, this is our only choice.&lt;/p&gt;
&lt;p&gt;Except, we do have threads in Emacs.
So, we can create our own event loop inside Emacs&amp;rsquo;s own event loop like this:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--background-scheduler&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make-thread&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/run&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-yield&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Personally, I wouldn&amp;rsquo;t recommend this unless the scheduler is sophisticated enough to avoid affecting emacs&amp;rsquo; performance.
This will run forever, and update all tasks that we&amp;rsquo;ve spawned with the &lt;code&gt;a/go&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a put %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;while-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b got %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b done&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;details&gt;
&lt;summary&gt;Log of the evaluation&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tweaking the channel&amp;rsquo;s buffer size can affect how these processes communicate, e.g. here&amp;rsquo;s the log with the buffer size of &lt;code&gt;3&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a put 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b got 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;b done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;This code spawns two lightweight processes communicating through the channel &lt;code&gt;ch&lt;/code&gt;.
The first process puts values into the channel and logs after the value is accepted.
The second one waits until values arrive in the channel, and logs the values it receives.&lt;/p&gt;
&lt;p&gt;When the first channel finishes with the internal &lt;code&gt;dotimes&lt;/code&gt; loop it closes the channel with &lt;code&gt;a/close!&lt;/code&gt;.
The second task then will complete once the channel is closed, because &lt;code&gt;a/&amp;lt;!&lt;/code&gt; will return &lt;code&gt;nil&lt;/code&gt; once the channel is exhausted.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s basically it!&lt;/p&gt;
&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;p&gt;So, what can we do with this kind of system?&lt;/p&gt;
&lt;p&gt;We can retrieve an URL in an asynchronous way with &lt;code&gt;url-retrieve&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url-retrieve&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://andreyor.st/2022-09-26-reproducible-research-with-org-mode-fennel-and-love.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-string&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;page size: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the callback, provided to the function, we set the value of the &lt;code&gt;ch&lt;/code&gt; channel to be the total length of the resulting buffer.
Then we close the channel, so it won&amp;rsquo;t be used again by anyone else.
The &lt;code&gt;a/go&lt;/code&gt; block runs asynchronously and waits til the channel has the value.
If we have the scheduler &lt;a href=&#34;#code-snippet--background-scheduler&#34;&gt;running in the background&lt;/a&gt;, the message will appear once the operation is done.&lt;/p&gt;
&lt;p&gt;The main point is that we can convert a callback-based interface to a channel-based interface with ease:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/url-retrieve&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Asynchronously retrieve the URL.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Returns a channel, containing the resulting string once the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;operation is complete.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url-retrieve&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;url&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;buffer-string&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then our system built on top of channels will be able to work with this kind of function in a simple way.
E.g., we can define an operation that will wait on multiple channels:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/alts!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Wait for multiple CHANNELS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Return the first one that completes along with the result.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channels&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/take!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;done&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;iter-yield&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, we may be required to manually yield from the &lt;code&gt;a/go&lt;/code&gt; at times, and this ruins the abstraction a bit, but it can be fixed with a proper channel implementation.
Anyhow, we can now do multiple requests simultaneously, and print the size of the fastest one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c1&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/url-retrieve&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://andreyor.st/posts/2023-01-09-comparison-of-manifold-and-clojurecoreasync/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c2&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/url-retrieve&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://andreyor.st/posts/2022-12-09-fixed-version-of-pipeline-async-and-unordered-pipeline-variants/&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c3&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/url-retrieve&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq-let&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/alts!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c3&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;page size: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;will-i-make-a-library-for-this&#34;&gt;Will I make a library for this?&lt;/h2&gt;
&lt;p&gt;Probably not, I already have one for Fennel, and I don&amp;rsquo;t want to maintain another one for Emacs, plus I&amp;rsquo;m not that good at Emacs Lisp.
I like the idea, but in its current state, it has a lot of places to be improved.
Already mentioned &lt;a href=&#34;https://github.com/skeeto/emacs-aio&#34; target=&#34;_blank&#34;&gt;emacs-aio&lt;/a&gt; is probably what you&amp;rsquo;d want to use if you want this kind of lightweight processes.
Though, I&amp;rsquo;d like to have such a library as a part of Emacs&amp;rsquo; core, tightly integrated with other core packages, such as &lt;code&gt;comint&lt;/code&gt; for example.
Still, I suggest you read the author&amp;rsquo;s explanation of their library principles here: &lt;a href=&#34;https://nullprogram.com/blog/2019/03/10/&#34; target=&#34;_blank&#34;&gt;https://nullprogram.com/blog/2019/03/10/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Again, all of the above is rather an experiment, an exploration of an alternative way of organizing asynchronous cooperative processes.
The channel interface described here was inspired by Clojure&amp;rsquo;s &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;core.async&lt;/code&gt; was in turn inspired by Go&amp;rsquo;s channels.
I, personally, like the idea of everything being a channel, and as you&amp;rsquo;ve seen in the last examples with &lt;code&gt;url-retrieve&lt;/code&gt;, channels can too act like a promise, except, unlike a promise you can&amp;rsquo;t continue re-reading the channel.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t get me wrong promises are fine, though I like them a bit less because you have to chain a lot of callbacks in a clever way, almost having a dedicated DSL for that.
The code with channels looks quite linear in my opinion, and I highly value this property when working with asynchronous code.&lt;/p&gt;
&lt;p&gt;Anyway, let&amp;rsquo;s hope Emacs will continue to advance, and its support for multithreading and concurrency will grow to be better and simpler to use.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Ad-hoc async in emacs-lisp via generators&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 01 Feb 2023 22:49:00 +0300</pubDate>
    </item><item>
      <title>Region bindings and common lisp modes</title>
      <link>https://andreyor.st/posts/2023-01-30-region-bindings-and-common-lisp-modes/</link>
      <guid>https://andreyor.st/posts/2023-01-30-region-bindings-and-common-lisp-modes/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve published two new packages for Emacs: - &lt;a href=&#34;https://github.com/andreyorst/region-bindings.el&#34; target=&#34;_blank&#34;&gt;region-bindings.el&lt;/a&gt; and &lt;a href=&#34;https://github.com/andreyorst/common-lisp-modes.el&#34; target=&#34;_blank&#34;&gt;common-lisp-modes.el&lt;/a&gt;.
Both are quite small and &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/commit/ae2101ba100d3181e97b9da74bb3c5f8a4ef4dd1&#34; target=&#34;_blank&#34;&gt;were&lt;/a&gt; a part of my configuration for a long time, but after small refactoring of my &lt;code&gt;init.el&lt;/code&gt; I&amp;rsquo;ve decided to extract them.&lt;/p&gt;
&lt;p&gt;The first one, &lt;code&gt;region-bindings&lt;/code&gt; is a from-scratch re-implementation of &lt;a href=&#34;https://github.com/fgallina/region-bindings-mode&#34; target=&#34;_blank&#34;&gt;region-bindings-mode&lt;/a&gt;.
This project had not seen development since 2014, and I had issues with how it works.
When I tried it I wasn&amp;rsquo;t using &lt;code&gt;transient-mark-mode&lt;/code&gt; (&lt;code&gt;tmm&lt;/code&gt;), yet, that package still activated its bindings, and did not properly disable it.
Even with &lt;code&gt;tmm&lt;/code&gt; enabled, it managed to leak its state when I used &lt;code&gt;isearch&lt;/code&gt;.
So I decided to make my own.&lt;/p&gt;
&lt;p&gt;The implementation is not too different, but I made sure that it works both with and without &lt;code&gt;tmm&lt;/code&gt;.
As an added bonus, it features a global minor mode and some pre-defined keybindings.&lt;/p&gt;
&lt;p&gt;I mostly use it with &lt;code&gt;puni&lt;/code&gt; and &lt;code&gt;multiple-cursors.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:bind&lt;/span&gt; ( &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:map&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings-mode-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni-wrap-round&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni-wrap-square&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni-wrap-curly&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;lt;&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni-wrap-angle&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;multiple-cursors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:bind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ( &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:map&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;region-bindings-mode-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-next-symbol-like-this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;N&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-next-like-this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-previous-symbol-like-this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-previous-like-this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-all-symbols-like-this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-all-like-this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;s&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/mark-all-in-region-regexp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;l&amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mc/edit-ends-of-lines&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second package is called &amp;ldquo;common lisp modes&amp;rdquo; but it has nothing to do with Common Lisp.
It&amp;rsquo;s a very small package that provides a minor mode that you can use to set up other packages that are common between various lisps.
So it&amp;rsquo;s not &amp;ldquo;common-lisp modes&amp;rdquo; but rather &amp;ldquo;common lisp-modes&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The main reason is that the &lt;code&gt;lisp-mode&lt;/code&gt; in Emacs is for Common Lisp and its derivatives that share the same syntax.
Unfortunately, other lisps like Clojure or Fennel can&amp;rsquo;t inherit from &lt;code&gt;lisp-mode&lt;/code&gt; and instead inherit their major modes from &lt;code&gt;prog-mode&lt;/code&gt;.
This works but comes at a cost that you can&amp;rsquo;t really add lisp-specific things that you want across all lisps, like &lt;code&gt;paredit&lt;/code&gt;, to the &lt;code&gt;prog-mode-hook&lt;/code&gt; because it will be enabled in other programming languages too, like in Erlang or OCaml, where it makes no sense.
There&amp;rsquo;s a &lt;code&gt;lisp-data-mode&lt;/code&gt; in Emacs, which can be used instead of &lt;code&gt;prog-mode&lt;/code&gt;, but there are already too many packages implemented in terms of &lt;code&gt;prog-mode&lt;/code&gt; and they don&amp;rsquo;t really need to change that, as they work fine.&lt;/p&gt;
&lt;p&gt;The same goes for most of the REPLs - they use variants of &lt;code&gt;comint-mode&lt;/code&gt; as a parent mode, and like &lt;code&gt;prog-mode&lt;/code&gt; comint is used for much more than lisp REPLs.
So again, it&amp;rsquo;s hard to configure common features specific to lisp REPLs only.&lt;/p&gt;
&lt;p&gt;Thus this package provides two minor modes &lt;code&gt;common-lisp-modes-mode&lt;/code&gt; and &lt;code&gt;common-repl-modes-mode&lt;/code&gt;, to which you can add hooks.
For example, my configuration does the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; actual configs omitted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;minibuffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-expression-minibuffer-setup&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elisp-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs-lisp-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-repl-mode&lt;/span&gt;) . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-data-mode&lt;/span&gt;) . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inf-lisp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inferior-lisp-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sly-mrepl-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-repl-mode&lt;/span&gt;) . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurec-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurescript-mode&lt;/span&gt;) . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-repl-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then I simply use &lt;code&gt;common-lisp-modes-mode-hook&lt;/code&gt; to enable common features:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nxml-mode&lt;/span&gt;) . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;common-lisp-modes-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Maybe there are not that many common modes in my configuration, but I still appreciate the fact that I don&amp;rsquo;t need to list all lisps I use in both &lt;code&gt;puni&lt;/code&gt; and &lt;code&gt;isayt&lt;/code&gt; configuration, like this, or keep a list somewhere else:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-expression-minibuffer-setup-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs-lisp-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-repl-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-data-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inferior-lisp-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sly-mrepl-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-repl-mode-hook-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurec-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurescript-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-repl-mode-hook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;puni-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:hook&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval-expression-minibuffer-setup-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;emacs-lisp-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel-repl-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lisp-data-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inferior-lisp-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sly-mrepl-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scheme-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;racket-repl-mode-hook-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurec-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojurescript-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cider-repl-mode-hook&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;isayt-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is harder to maintain, as I&amp;rsquo;ll need to add new lisps I want to try out or remove lisps once I&amp;rsquo;m done playing with them to prevent cluttering.
I already have a lot of lisps I use semi-regularly, so I want the process to be more seamless.&lt;/p&gt;
&lt;p&gt;I hope these packages will be helpful for others too, but I don&amp;rsquo;t think I&amp;rsquo;m going to submit them to MELPA or (Non-GNU)ELPA.
You can use &lt;code&gt;straight.el&lt;/code&gt;, &lt;code&gt;el-get&lt;/code&gt;, &lt;code&gt;quelpa&lt;/code&gt; and such to install these directly from git.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Region bindings and common lisp modes&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 30 Jan 2023 20:02:00 +0300</pubDate>
    </item><item>
      <title>Compiling Clojure projects in Emacs</title>
      <link>https://andreyor.st/posts/2023-01-10-compiling-clojure-projects-in-emacs/</link>
      <guid>https://andreyor.st/posts/2023-01-10-compiling-clojure-projects-in-emacs/</guid>
      <description>&lt;p&gt;Another post in the not-so-series about Emacs configuration.
Today I will describe my configuration for managing the &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; variable in a way that is meaningful for the current project I&amp;rsquo;m working on.
Some time ago I &lt;a href=&#34;https://www.reddit.com/r/emacs/comments/xvm0ql/tips_on_managing_compilationerrorregexpalist/&#34; target=&#34;_blank&#34;&gt;faced a problem&lt;/a&gt; that the &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; variable contains far too many entries for different languages by default.
Since then, I&amp;rsquo;ve figured out how to solve this problem for myself, so I decided to explain it here, with the hope that it will be useful for others.
Actually, most of this isn&amp;rsquo;t Clojure-specific at all and can be applied to any other language as easily.
Yet, there will be some parts that are useful specifically for Clojure projects but may also benefit other languages that share the same problem with file paths.&lt;/p&gt;
&lt;p&gt;For those unfamiliar with the &lt;code&gt;compile&lt;/code&gt; command in Emacs, it is essentially a way of running external programs, such as &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;lein&lt;/code&gt;, or anything else, really.
There&amp;rsquo;s a similar command in Emacs, called &lt;code&gt;async-shell-command&lt;/code&gt;, which also can be used for that, but the key difference between these two is that the buffer, created by &lt;code&gt;compile&lt;/code&gt; automatically enters &lt;code&gt;compile-mode&lt;/code&gt;.
This mode is responsible for highlighting and counting errors, and warnings, and provides ways of jumping to problems directly from that buffer.
And to configure how the errors are recognized we need to use the &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; and &lt;code&gt;compilation-error-regexp-alist-alist&lt;/code&gt; variables.
The first one contains symbols, that we want to check against, and the second one stores pairs with such symbols and the regular expression used to match the particular error.
For example, to compile a Guile project, we can set this variable to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-error-regexp-alist&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guile-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guile-line&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;compilation-error-regexp-alist-alist&lt;/code&gt; contains, among others, these two entries:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#39;(&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guile-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^In \\(.+\\..+\\):\n&amp;#34;&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;guile-line&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^ *\\([0-9]+\\): *\\([0-9]+\\)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; 1 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But now, that the &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; variable is set to contain only Guile-related entries, the compilation buffer will only pick up problems that match these regular expressions from &lt;code&gt;compilation-error-regexp-alist-alist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The system may look simple, however, there&amp;rsquo;s a problem.
The &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; variable is not buffer-local, and while you can make it, you still need a way to know what kind of project you&amp;rsquo;re compiling and some hook to set these variables right before the compilation starts.
And even if we knew, we would need a way of setting this variable on per project basis to some values that are &lt;em&gt;meaningful&lt;/em&gt; for the project.
So how can we do that?&lt;/p&gt;
&lt;h2 id=&#34;the-compile-function&#34;&gt;The &lt;code&gt;compile&lt;/code&gt; function&lt;/h2&gt;
&lt;p&gt;To answer our questions, let&amp;rsquo;s look at the &lt;code&gt;compile&lt;/code&gt; function signature:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we check the documentation for this function, there&amp;rsquo;s a vague line about the &lt;code&gt;comint&lt;/code&gt; argument:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If optional second arg &lt;code&gt;COMINT&lt;/code&gt; is &lt;code&gt;t&lt;/code&gt; the buffer will be in Comint mode with
&lt;code&gt;‘compilation-shell-minor-mode’&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, this documentation isn&amp;rsquo;t exactly on point.
If we look at the body of this function, we&amp;rsquo;ll see that the only time the &lt;code&gt;comint&lt;/code&gt; argument is used is at the end of the function when we call the &lt;code&gt;compilation-start&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compile&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-start&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;comint&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The signature of &lt;code&gt;compilation-start&lt;/code&gt; tells us that its second argument is actually called &lt;code&gt;mode&lt;/code&gt; and it is described as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;MODE&lt;/code&gt; is the major mode to set in the compilation buffer.  Mode
may also be &lt;code&gt;t&lt;/code&gt; meaning use &lt;code&gt;‘compilation-shell-minor-mode’&lt;/code&gt; under &lt;code&gt;‘comint-mode’&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So there&amp;rsquo;s a way of setting a different mode for the compilation buffer.
And that&amp;rsquo;s exactly what we need to solve our problem.&lt;/p&gt;
&lt;h2 id=&#34;defining-a-new-major-mode-for-compilation-of-a-specific-language&#34;&gt;Defining a new major mode for compilation of a specific language&lt;/h2&gt;
&lt;p&gt;So this step can be done for any language, not just Clojure.
If you frequently compile, say, Lua, you may want to analyze Lua stack traces, and prevent other regular expressions from the &lt;code&gt;compilation-error-regexp-alist&lt;/code&gt; to interfere.
So to workaround this, you can simply create a mode, which sets its own local variables to the values, needed by &lt;code&gt;compile&lt;/code&gt;.
Here&amp;rsquo;s a mode I&amp;rsquo;ve defined for Clojure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Alist that specifies how to match errors in Clojure compiler output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;See &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`compilation-error-regexp-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; for more information.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist-alist&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Alist of values for &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`clojure-compilation-error-regexp-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Current root of the project being compiled.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-files&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Current list of files belonging to the project being compiled.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-derived-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Clojure(Script) Compilation&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Compilation mode for Clojure output.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-error-regexp-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-error-regexp-alist-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist-alist&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-current&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-files&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll explain why the other variables are needed later, our main focus here is &lt;code&gt;clojure-compilation-error-regexp-alist&lt;/code&gt; and &lt;code&gt;clojure-compilation-error-regexp-alist-alist&lt;/code&gt; ones.&lt;/p&gt;
&lt;p&gt;Now we can define our rules for highlighting.
For example, if you use &lt;a href=&#34;https://github.com/clj-kondo/clj-kondo&#34; target=&#34;_blank&#34;&gt;clj-kondo&lt;/a&gt;, an excellent linter for Clojure, you might want to capture the filename from its messages and distinguish warnings and errors.
You can do it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-kondo-warning&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-kondo-error&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;#39;((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-kondo-error&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^\\(/[^:]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\): error&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         1 2 3 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clj-kondo-warning&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^\\(/[^:]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\): warning&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           1 2 3 1)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because our &lt;code&gt;clojure-compilation-mode&lt;/code&gt; mode is derived from the &lt;code&gt;compilation-mode&lt;/code&gt;, we can use everything that is defined in &lt;code&gt;compilation-mode&lt;/code&gt;, so upon activation, we locally set the &lt;code&gt;regexp-alist&lt;/code&gt; variables to our predefined Clojure-related rules.
The last thing left is to teach Emacs how to automatically enable this mode, and this can be done via &lt;code&gt;project.el&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;tweaking-project-dot-el-to-help-compile-understand-what-mode-to-use&#34;&gt;Tweaking &lt;code&gt;project.el&lt;/code&gt; to help &lt;code&gt;compile&lt;/code&gt; understand what mode to use&lt;/h2&gt;
&lt;p&gt;As the title of this section suggests, we&amp;rsquo;re going to teach &lt;code&gt;project.el&lt;/code&gt; new tricks.
But why &lt;code&gt;project.el&lt;/code&gt; all of a sudden?
Didn&amp;rsquo;t I say that we&amp;rsquo;re going to use &lt;code&gt;compile&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Well, I mainly use &lt;code&gt;project-compile&lt;/code&gt; because it does an appropriate thing from the project root.
I don&amp;rsquo;t use &lt;a href=&#34;https://github.com/bbatsov/projectile&#34; target=&#34;_blank&#34;&gt;projectile&lt;/a&gt;, which is another project management package for Emacs, so if you use it, you&amp;rsquo;re on your own here.&lt;/p&gt;
&lt;p&gt;The first thing we need to do is create a new variable in the &lt;code&gt;project&lt;/code&gt; group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-compilation-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Mode to run the &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`compile&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; command with.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;symbol&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:safe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;symbolp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we&amp;rsquo;re going to advise the &lt;code&gt;compilation-start&lt;/code&gt; function, which is used by &lt;code&gt;compile&lt;/code&gt; and &lt;code&gt;recompile&lt;/code&gt; functions to use this mode if the mode wasn&amp;rsquo;t passed explicitly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-start&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:filter-args&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;use-project-compilation-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cmd&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cadr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cddr&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mode&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-compilation-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cmd&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-compilation-mode&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Basically, we reconstruct the argument list with the mode we&amp;rsquo;re interested in.
Unfortunately, the &lt;code&gt;project-compile&lt;/code&gt; function doesn&amp;rsquo;t support specifying compilation mode, and calls &lt;code&gt;compile&lt;/code&gt; without any arguments, so we kinda have to do it this way.
As a bonus, it will also work for &lt;code&gt;recompile&lt;/code&gt;, which gets called when you press &lt;code&gt;g&lt;/code&gt; in the compilation buffer.
It would be nicer, if &lt;code&gt;project-compile&lt;/code&gt; accepted the same arguments as &lt;code&gt;compile&lt;/code&gt;, and there was a &lt;code&gt;project-recompile&lt;/code&gt; function, so we could do things without using &lt;code&gt;define-advice&lt;/code&gt;, but we have to work with what we have&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;This advice only does anything to the arguments if the &lt;code&gt;mode&lt;/code&gt; wasn&amp;rsquo;t set to a non-nil value, and when &lt;code&gt;project-compilation-mode&lt;/code&gt; is set.
Which, we can do via &lt;code&gt;.dir-locals.el&lt;/code&gt; or &lt;code&gt;.dir-locals-2.el&lt;/code&gt; if the first one is under version control:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; Directory Local Variables            -*- no-byte-compile: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; For more information see (info &amp;#34;(emacs) Directory Variables&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; . ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-compilation-mode&lt;/span&gt; . &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-mode&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we compile this project, we&amp;rsquo;ll trigger our advice, which will update args, and compilation will enter &lt;code&gt;clojure-compilation-mode&lt;/code&gt;.
The errors will now use the rules we&amp;rsquo;ve defined for the current mode, and the process is automatic enough.
Alternatively, &lt;code&gt;project-compilation-mode&lt;/code&gt; can be set via a mode hook:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-mode-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq-local&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-compilation-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation-mode&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The downside of this method is that when called from the non-Clojure buffer, the value of this variable will be unset.&lt;/p&gt;
&lt;h2 id=&#34;dynamically-extracting-filenames-from-compiler-output&#34;&gt;Dynamically extracting filenames from compiler output&lt;/h2&gt;
&lt;p&gt;Example configuration for &lt;code&gt;clj-kondo&lt;/code&gt; from above is nice, but there&amp;rsquo;s a problem.
&lt;code&gt;Clj-kondo&lt;/code&gt; works with files, but when actually compiling Clojure code with the compiler, there is no actual project information left.
Instead, we have namespace information, which is not exactly mapped to files in the project.
E.g. we can get reflection warnings from something outside of our project, like from a dependency or a build system plugin, which would look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lein kaocha
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, /tmp/form-init5271780372383707418.clj:1:1014 - call to static method invokeStaticMethod on clojure.lang.Reflector can&amp;#39;t be resolved (argument types: unknown, java.lang.String, unknown).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, kaocha/runner.clj:156:73 - call to java.io.File ctor can&amp;#39;t be resolved.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reflection warning, test_project/core.clj:8:3 - reference to field getMessage can&amp;#39;t be resolved.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, I&amp;rsquo;m using &lt;a href=&#34;https://github.com/lambdaisland/kaocha&#34; target=&#34;_blank&#34;&gt;kaocha&lt;/a&gt;, a test runner for Clojure which has some problems with reflection.
Nothing serious, but when &lt;code&gt;*warn-on-reflection*&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt; in a lein profile, this gets in the log.
However, these messages are useful for us, as they demonstrate that even though reflection warnings have filename and line/column information, they can be outside of our project root.&lt;/p&gt;
&lt;p&gt;Another thing to notice is that the files that do belong to our project don&amp;rsquo;t use the full path from the project root.
In other words full path from the project root to the &lt;code&gt;core.clj&lt;/code&gt; should be &lt;code&gt;src/test_project/core.clj&lt;/code&gt;.
This is important, because there may be other directories, which contain Clojure files, for example, &lt;code&gt;test/test_project/bar.clj&lt;/code&gt;, which would be represented as just &lt;code&gt;test_project/bar.clj&lt;/code&gt; in the compilation log.
Names of such directories are arbitrary and can be configured for each project separately.&lt;/p&gt;
&lt;p&gt;So, in order to jump to such a file from this kind of log entry, we need to figure out if this file belongs to our project.
What&amp;rsquo;s great about &lt;code&gt;compilation-error-regexp-alist-alist&lt;/code&gt; is that instead of specifying a group that represents the path part in the regular expression, we can specify a function to call in the compilation buffer.
This function is called from the end of the matched part of our regular expression, so we can do a simple search for the filename from there.
Then we can look if this path can be found in a set of all project files, and if it is, we return the path and the directory relative to the project root.
Here&amp;rsquo;s the function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename-fn&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rule-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Create a function that gets the filename from the error message.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;RULE-NAME is a symbol in &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`clojure-compilation-error-regexp-alist-alist&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;It is used to obtain the regular expression, which is used for a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;backward search in order to extract the filename from the first
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;group.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Get a filename from the error message and compute the relative directory.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;regexp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;car&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rule-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-error-regexp-alist-alist&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-match-data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;re-search-backward&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;regexp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring-no-properties&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-string&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;seq-find&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-suffix-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project-files&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path-in-project&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-project&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;substring&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path-in-project&lt;/span&gt; 0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filename&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can see why &lt;code&gt;clojure-compilation-mode&lt;/code&gt; sets the &lt;code&gt;clojure-compilation-project&lt;/code&gt; and &lt;code&gt;clojure-compilation-project-files&lt;/code&gt; variables.
We reuse them for every line that matches our regular expression, so it&amp;rsquo;s better to cache them beforehand since project sources rarely change during compilation.
Here&amp;rsquo;s how we use it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rule-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-reflection-warning&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation-error-regexp-alist&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rule-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;clojure-compilation-error-regexp-alist-alist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rule-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^Reflection warning,[[:space:]]*\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\).*$&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure-compilation-filename-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rule-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 2 3 2)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/e01919d4b57fd215807fb5cc4f989cb67e4f5a8c/.config/emacs/init.el#L1650-1666&#34; target=&#34;_blank&#34;&gt;further automated&lt;/a&gt; into a separate function which sets both alists.&lt;/p&gt;
&lt;p&gt;This function creates a closure over this regular expression and uses it to find the path to the file.
If the path is not a part of the project, we just return it as is.
Emacs will ask us for the base directory to search this file in, which isn&amp;rsquo;t the best solution, but we can&amp;rsquo;t do much here, given that it&amp;rsquo;s impossible to know from which jar the namespace came.&lt;/p&gt;
&lt;p&gt;My complete configuration for Clojure compilation can be found &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/e01919d4b57fd215807fb5cc4f989cb67e4f5a8c/.config/emacs/init.el#L1668-1758&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I haven&amp;rsquo;t signed the copyright assignment to FSF so I can&amp;rsquo;t really contribute to Emacs.
Perhaps, small changes, like adding a new parameter to a function may not require signing the copyright, but I often feel that the advice system is in Emacs exactly for such occasions.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Compiling Clojure projects in Emacs&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 10 Jan 2023 22:28:00 +0300</pubDate>
    </item><item>
      <title>Comparison of manifold and clojure.core.async</title>
      <link>https://andreyor.st/posts/2023-01-09-comparison-of-manifold-and-clojurecoreasync/</link>
      <guid>https://andreyor.st/posts/2023-01-09-comparison-of-manifold-and-clojurecoreasync/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been into &lt;a href=&#34;https://github.com/clojure/core.async&#34; target=&#34;_blank&#34;&gt;clojure.core.async&lt;/a&gt; lately, and I like the overall design of this library - it&amp;rsquo;s simple and easy to understand.
However, at work, we use &lt;a href=&#34;https://github.com/clj-commons/manifold&#34; target=&#34;_blank&#34;&gt;manifold&lt;/a&gt; in our projects, mainly because it is supported by the &lt;a href=&#34;https://github.com/clj-commons/aleph&#34; target=&#34;_blank&#34;&gt;aleph&lt;/a&gt; server, which was chosen because it can asynchronously read data coming from the client.
Today that&amp;rsquo;s beside the point, what matters is that &lt;code&gt;manifold&lt;/code&gt; and &lt;code&gt;core.async&lt;/code&gt; use different approaches for building concurrent code, and I will try to explain both and compare the two.
Let&amp;rsquo;s start with how &lt;code&gt;core.async&lt;/code&gt; works on the surface.&lt;/p&gt;
&lt;h2 id=&#34;core-dot-async-basics&#34;&gt;&lt;code&gt;core.async&lt;/code&gt; basics&lt;/h2&gt;
&lt;p&gt;The minimum you need to know about &lt;code&gt;core.async&lt;/code&gt; is how to properly use channels because it is a central abstraction in this library.
Everything is represented as a channel, which is basically a queue of puts, a queue of takes, plus an optional buffer queue that holds values.
The basic idea is that you share channels between asynchronous threads, and when one thread puts a value to the channel it parks until someone else takes value off the channel (if there&amp;rsquo;s no buffer).
There are a lot of things that can be built on top of this kind of abstraction, and in reality programming with &lt;code&gt;core.async&lt;/code&gt; looks more like programming with queues.&lt;/p&gt;
&lt;p&gt;I will expand upon the info above later when I&amp;rsquo;ll go to the actual code, but this should be fine as an abstract introduction.
Now, let&amp;rsquo;s look at &lt;code&gt;manifold&lt;/code&gt; in a similar way.&lt;/p&gt;
&lt;h2 id=&#34;manifold-basics&#34;&gt;&lt;code&gt;manifold&lt;/code&gt; basics&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Manifold&lt;/code&gt; actually has a similar abstraction, but it is called a &lt;code&gt;stream&lt;/code&gt;.
Streams can be sources, sinks, or both at the same time,  and they provide a similar interface to &lt;code&gt;core.async&lt;/code&gt; where you can put a value to or take a value from the stream, as well as do a lot of different operations on streams directly, e.g connecting, filtering, e.t.c.
In addition to streams, however, &lt;code&gt;manifold&lt;/code&gt; provides an additional abstraction, called a &lt;code&gt;deferred&lt;/code&gt;.
It is a lot like Clojure&amp;rsquo;s built-in &lt;code&gt;promise&lt;/code&gt;, e.g. you can use &lt;code&gt;defer&lt;/code&gt; on it, and it will cache the value that was delivered to it, but in addition, you can attach callbacks onto deferreds, and they also can represent errors.&lt;/p&gt;
&lt;p&gt;What sets &lt;code&gt;manifold&lt;/code&gt; apart is that this library is aimed to be a translation layer between different asynchronous implementations.
For example, you can convert &lt;code&gt;core.async&lt;/code&gt; channels into sources and act upon them as you would on &lt;code&gt;manifold&lt;/code&gt; streams.
The same can be done with lazy sequences or Java&amp;rsquo;s &lt;code&gt;BlockingQueues&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, that we have a general understanding of both, let&amp;rsquo;s look at how the same code can be written using both libraries.
The code in examples won&amp;rsquo;t involve complex scenarios, but I think the patterns I&amp;rsquo;ll show are general enough to be seen in most of the code you&amp;rsquo;ll see when dealing with these libraries.&lt;/p&gt;
&lt;h2 id=&#34;channels-vs-deferreds&#34;&gt;Channels vs deferreds&lt;/h2&gt;
&lt;p&gt;It may seem weird, that I&amp;rsquo;m going to compare &lt;code&gt;core.async&lt;/code&gt; channels to &lt;code&gt;manifold&lt;/code&gt; deferreds instead of streams, but that&amp;rsquo;s how we use &lt;code&gt;manifold&lt;/code&gt; at work, so I&amp;rsquo;m much more familiar with deferreds.
What you should understand, however, is that both &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt; aim at giving you a way of writing code that &lt;em&gt;looks&lt;/em&gt; linear, even though it isn&amp;rsquo;t, however, the ways of doing so differ quite a lot between these libraries.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start simple - say, we want to off-load an abstract operation to another asynchronous thread, and once it completes we&amp;rsquo;d continue working with a result in our asynchronous thread.
First, how do you actually create a &amp;ldquo;thread&amp;rdquo;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; in &lt;code&gt;core.async&lt;/code&gt;?
The answer is a &lt;code&gt;go&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &amp;#39;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core.async&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, nothing fancy for now.
The &lt;code&gt;offloaded-task&lt;/code&gt; function spawns an asynchronous thread which immediately parks on a &lt;code&gt;timeout&lt;/code&gt; operation, simulating some asynchronous work that takes time, like a web request, for example.
Then it just returns a random integer.
The result of calling this function is a &lt;strong&gt;channel&lt;/strong&gt;, created by the &lt;code&gt;go&lt;/code&gt; macro.
Once the  &lt;code&gt;rand-int&lt;/code&gt; completes, this channel will contain the resulting number.&lt;/p&gt;
&lt;p&gt;Then, we create a second &lt;code&gt;go&lt;/code&gt; &lt;em&gt;thread&lt;/em&gt;.
Inside it, we write a &lt;code&gt;let&lt;/code&gt; block, as we normally would, we then call our &lt;code&gt;offloaded-task&lt;/code&gt; and park until it completes.
Once it is complete, we print it and return the value.
The result is again a channel, which will contain the value of &lt;code&gt;res&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s this &lt;code&gt;&amp;lt;!&lt;/code&gt; thing actually does?
Well, this is a lot of machinery that happens inside the &lt;code&gt;go&lt;/code&gt; macro.
You don&amp;rsquo;t really need to know it in detail, but &lt;code&gt;go&lt;/code&gt; macro transforms this linear code into a callback-based state-machine, and each time it meets &lt;code&gt;&amp;lt;!&lt;/code&gt; it transforms the rest of the code to a callback, which will be executed once a value appeared on the channel.
So, essentially, &lt;code&gt;go&lt;/code&gt; macro is doing inversion of control for us, transforming our linear code into the code which can be executed in an asynchronous manner.
I may be a bit incorrect here on the details, but that&amp;rsquo;s essentially how I understand the &lt;code&gt;go&lt;/code&gt; block.
Here&amp;rsquo;s a &lt;a href=&#34;https://www.youtube.com/watch?v=R3PZMIwXN_g&#34; target=&#34;_blank&#34;&gt;much more thorough and complicated explanation&lt;/a&gt; by the author of the &lt;code&gt;go&lt;/code&gt; block.
It comes in two parts, so if you want to know more, make sure you&amp;rsquo;ve watched the &lt;a href=&#34;https://www.youtube.com/watch?v=SI7qtuuahhU&#34; target=&#34;_blank&#34;&gt;second part&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s look at the same thing, but with &lt;code&gt;manifold&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &amp;#39;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold.deferred&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/deferred&lt;/span&gt;) 1000 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks less linear when compared to &lt;code&gt;core.async&lt;/code&gt; version, mainly because we specify callbacks as literal callbacks.
However, &lt;code&gt;manifold&lt;/code&gt; provides the &lt;code&gt;let-flow&lt;/code&gt; macro, which I, personally, never use, but for the sake of completeness we can change the code to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/let-flow&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deferred&lt;/span&gt;) 1000 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/let-flow&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This now looks even more linear than the &lt;code&gt;core.async&lt;/code&gt; version, thanks to the &lt;code&gt;let-flow&lt;/code&gt; macro, which basically expands to a similar code that we&amp;rsquo;ve manually written before, except it uses &lt;code&gt;d/zip&lt;/code&gt; to await multiple deferreds (even though right now there&amp;rsquo;s only one):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/zip&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, what&amp;rsquo;s happening here?
In case of &lt;code&gt;core.async&lt;/code&gt; everything was represented as a channel.
In the case of &lt;code&gt;manifold&lt;/code&gt;, however, everything was represented as deferreds.
Functions such as &lt;code&gt;chain&lt;/code&gt;, and &lt;code&gt;timeout!&lt;/code&gt;, and later the &lt;code&gt;let-flow&lt;/code&gt; macro produce a &lt;code&gt;deferred&lt;/code&gt;, which represents a value that eventually will be there.
As you can see, &lt;code&gt;chain&lt;/code&gt; is the central mechanism here, as we can literally &lt;em&gt;chain&lt;/em&gt; tasks, each of which will consume deferred when it&amp;rsquo;s ready and produce another deferred upon completion.
This allows us to add more and more actions to a given deferred, which will be executed linearly.
And &lt;code&gt;let-flow&lt;/code&gt; simply provides a more convenient interface.&lt;/p&gt;
&lt;h3 id=&#34;manifold-streams-but-they-re-also-deferreds&#34;&gt;&lt;code&gt;manifold&lt;/code&gt; streams but they&amp;rsquo;re also deferreds&lt;/h3&gt;
&lt;p&gt;We can, of course, do the same thing using streams:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &amp;#39;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold.stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/stream&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/deferred&lt;/span&gt;) 1000 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/take!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But again, as you can see we still use &lt;code&gt;chain&lt;/code&gt; because operations on streams are always asynchronous and return deferreds.
It works this way, because &lt;code&gt;manifold&lt;/code&gt; is mainly based on executors and callbacks attached to deferreds, so streams share the API and use deferreds when possible.&lt;/p&gt;
&lt;h2 id=&#34;some-technical-differences-between-core-dot-async-and-manifold&#34;&gt;Some technical differences between &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now, as we&amp;rsquo;ve seen the basic usage of both libraries, we can talk about some technical differences in their implementation.
The most prominent difference is that &lt;code&gt;core.async&lt;/code&gt; supports ClojureScript out of the box.
There is a version of &lt;code&gt;manifold&lt;/code&gt; for ClojureScript, &lt;a href=&#34;https://github.com/dm3/manifold-cljs&#34; target=&#34;_blank&#34;&gt;manifold-cljs&lt;/a&gt;, however, it has some differences and missing functionality, like &lt;code&gt;let-flow&lt;/code&gt;.
So if you want a cross-platform library for asynchronous programming, I believe &lt;code&gt;core.async&lt;/code&gt; is in the lead here for now.&lt;/p&gt;
&lt;h3 id=&#34;function-boundaries&#34;&gt;Function boundaries&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;core.async&lt;/code&gt;, however, has, possibly, a pretty serious design flaw, or at least one can look at it that way.
The mentioned &lt;code&gt;go&lt;/code&gt; macro &lt;a href=&#34;https://www.clojure.org/guides/core_async_go#_unsupported_constructs_and_other_limitations_in_go_blocks&#34; target=&#34;_blank&#34;&gt;can&amp;rsquo;t go over function boundaries&lt;/a&gt;, because there&amp;rsquo;s no way to transform code to a state machine in a meaningful way when parking happens effectively in a completely different stack frame.
Thus, you can&amp;rsquo;t do something like this in &lt;code&gt;core.async&lt;/code&gt; without additional &lt;code&gt;go&lt;/code&gt; blocks and extra parking:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/stream&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; feed all stream values through `println`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/consume&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;partial &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; 10 #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In &lt;code&gt;core.async&lt;/code&gt; you&amp;rsquo;d have to do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; NOTE: you can&amp;#39;t do (fn [val] (a/&amp;gt;! c val)) here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; 10 #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; or, better&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; 10 #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, this is not a proper way of writing such code, just a demonstration that in order to do a non-blocking put with &lt;code&gt;&amp;gt;!&lt;/code&gt; an additional &lt;code&gt;go&lt;/code&gt; block can be needed, when crossing function boundaries.
Documentation for &lt;code&gt;core.async&lt;/code&gt; &lt;a href=&#34;https://clojure.org/guides/core_async_go#_general_advice&#34; target=&#34;_blank&#34;&gt;suggests&lt;/a&gt; that in this kind of situation you can just use &lt;code&gt;put!&lt;/code&gt; to which &lt;code&gt;&amp;gt;!&lt;/code&gt; compiles after the macroexpansion of &lt;code&gt;go&lt;/code&gt;:
But this kind of code doesn&amp;rsquo;t really respect the back-pressure and can lead to an error when too many puts were enqueued.
The same point about back-pressure goes for &lt;code&gt;manifold&lt;/code&gt; version from above too.&lt;/p&gt;
&lt;p&gt;In both cases &lt;code&gt;go&lt;/code&gt; and &lt;code&gt;chain&lt;/code&gt; around &lt;code&gt;mapv&lt;/code&gt; are not necessary, in fact, they&amp;rsquo;re both harmful because we&amp;rsquo;re basically putting a synchronous loop inside an asynchronous thread.
Such threads run on a limited thread pool, which can lead to locking a thread for a long enough time to cause problems across the whole system.
This code may look like it does things asynchronously, given that both &lt;code&gt;s/put!&lt;/code&gt; and &lt;code&gt;a/put!&lt;/code&gt; are non-blocking, and we&amp;rsquo;re inside &lt;code&gt;go&lt;/code&gt; / &lt;code&gt;chain&lt;/code&gt; context, but it is not.&lt;/p&gt;
&lt;p&gt;A better way to write both examples would be:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--loops&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; manifold&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/stream&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/consume&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/loop&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vals &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; 10 #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; core.async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vals &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeatedly&lt;/span&gt; 10 #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[[&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;val &lt;/span&gt;&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vals&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In these examples, the code properly parks itself on &lt;code&gt;s/put!&lt;/code&gt; and &lt;code&gt;a/&amp;gt;!&lt;/code&gt;, when the consumer isn&amp;rsquo;t ready to accept the value or the buffer is full (if any).&lt;/p&gt;
&lt;p&gt;So why did I say that &lt;code&gt;core.async&lt;/code&gt; has a design flaw at the beginning of this section?
Well, if you look at the thing that &lt;code&gt;go&lt;/code&gt; macro does with your code, and if you&amp;rsquo;re familiar with other languages, such as Lua or Python, you might get the idea that what the &lt;code&gt;go&lt;/code&gt; macro really tries to do is to create something similar to coroutines or generators.&lt;/p&gt;
&lt;p&gt;In Lua, a coroutine is an ordinary function with the only difference that it can pause its execution when its body calls the &lt;code&gt;yield&lt;/code&gt; function, and then &lt;code&gt;continue&lt;/code&gt; its execution when desired.
Pythons generators work in a similar way.&lt;/p&gt;
&lt;p&gt;So in Lua, it would be possible to write such a system without complex transformations to state machines, the &lt;code&gt;&amp;gt;!&lt;/code&gt; or &lt;code&gt;&amp;lt;!&lt;/code&gt; functions would simply &lt;code&gt;yield&lt;/code&gt; from the current coroutine stack frame, and then the scheduler will resume them when needed.
This is how &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-async&#34; target=&#34;_blank&#34;&gt;my library&lt;/a&gt; for Fennel works, and it doesn&amp;rsquo;t have the same limitation as &lt;code&gt;core.async&lt;/code&gt;, as you can yield across function boundaries.
As far as I understand this is also how new virtual threads in the &lt;a href=&#34;https://blogs.oracle.com/javamagazine/post/going-inside-javas-project-loom-and-virtual-threads&#34; target=&#34;_blank&#34;&gt;upcoming Project Loom&lt;/a&gt; work, and thus it will be possible to use them with things like agents.
&lt;code&gt;core.async&lt;/code&gt; still has the advantage that it will work on runtimes that have neither coroutines nor threads, such as JavaScript.&lt;/p&gt;
&lt;h3 id=&#34;iteration&#34;&gt;Iteration&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;#code-snippet--loops&#34;&gt;previous example&lt;/a&gt; shows another difference between &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt; - iteration handling.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;go-loop&lt;/code&gt; macro simply expands to &lt;code&gt;(go (loop [] ...))&lt;/code&gt;, and parking is handled in the same way, the rest of the loop is transformed into a callback, which is attached to a channel.
This model is simple to understand and obeys the same restrictions as an ordinary &lt;code&gt;loop&lt;/code&gt; special in Clojure.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;manifold&lt;/code&gt;, however, we&amp;rsquo;re required to use &lt;code&gt;d/loop&lt;/code&gt;, which is a different implementation of a &lt;code&gt;loop&lt;/code&gt;, implemented as a macro.
This macro expands into an ordinary &lt;code&gt;loop&lt;/code&gt; that runs on an asynchronous thread-pool, but inside that loop there&amp;rsquo;s a &lt;code&gt;cond&lt;/code&gt; which properly manages deferreds, thus parking itself instead of blocking.
It relies on the fact that somebody will call the &lt;code&gt;d/recur&lt;/code&gt; function which returns doesn&amp;rsquo;t do anything by itself.
Instead, it returns an object which is an instance of &lt;code&gt;manifold.deferred.Recur&lt;/code&gt; that &lt;code&gt;d/loop&lt;/code&gt; expects.
Once it sees such an object, it goes to the next iteration.&lt;/p&gt;
&lt;p&gt;This method allows us to get fancy since we are no longer required to use &lt;code&gt;recur&lt;/code&gt; in the same lexical scope of &lt;code&gt;loop&lt;/code&gt;, and we can actually return it from any other function.
For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/deferred&lt;/span&gt;) 100 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 50)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s &amp;lt; 50, retrying&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s &amp;gt; 50, stop&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max retry count exceeded&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This actually allows us to build code, that has a lot of logic scattered across different functions, each of which, for example, may decide to retry the whole thing.
In &lt;code&gt;core.async&lt;/code&gt; this can be done as well, except it would require creating a custom API, e.g by passing a map that has a value under the &lt;code&gt;:val&lt;/code&gt; key, and if it is equal to, say, &lt;code&gt;::recur&lt;/code&gt; then we need to call real &lt;code&gt;recur&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 100))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;100)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 50)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s &amp;lt; 50, retrying&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:val&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt;)]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s &amp;gt; 50, stop&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;offloaded-task&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;retries&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;identical? &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:val&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;::recur&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nth &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:args&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) 0)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;max retry count exceeded&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, definitively doable, &lt;code&gt;manifold&lt;/code&gt; just has a dedicated API for that which goes through all the hoops for you.
Though it&amp;rsquo;s better to avoid explicit iteration in both libraries, and instead use pipelining facilities that do the processing of items.&lt;/p&gt;
&lt;h3 id=&#34;dynamic-binding&#34;&gt;Dynamic binding&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m not entirely sure about this but as it seems &lt;code&gt;core.async&lt;/code&gt; works better with dynamic scoping, while &lt;code&gt;manifold&lt;/code&gt; doesn&amp;rsquo;t work with it at all.
Though a lot of macros in &lt;code&gt;manifold&lt;/code&gt; generate calls to &lt;code&gt;bound-fn&lt;/code&gt;, which should capture the dynamic scope, perhaps, it&amp;rsquo;s a responsibility of a user when you use plain &lt;code&gt;d/chain&lt;/code&gt;.
I&amp;rsquo;m not a big fan of &lt;code&gt;bound-fn&lt;/code&gt; so most of the time when working with &lt;code&gt;manifold&lt;/code&gt; I pass such bindings explicitly as function arguments.
Here&amp;rsquo;s a demonstration of using a dynamically bound var &lt;code&gt;*token*&lt;/code&gt; in both &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dynamic&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/deferred&lt;/span&gt;) 100 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some: headers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server-async&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core-async&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server-async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt; 1337] @(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold&lt;/span&gt; 42))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; {:headers &amp;#34;some: headers&amp;#34;, :body &amp;#34;42&amp;#34;, :token 42}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt; 1337] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core-async&lt;/span&gt; 42)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; {:headers &amp;#34;some: headers&amp;#34;, :body &amp;#34;42&amp;#34;, :token 1337}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, in &lt;code&gt;manifold&lt;/code&gt;&amp;rsquo;s case, the &lt;code&gt;:token&lt;/code&gt; key holds the root binding value of &lt;code&gt;*token*&lt;/code&gt; which is &lt;code&gt;42&lt;/code&gt;.
In &lt;code&gt;core.async&lt;/code&gt; case, the binding value is properly captured by the &lt;code&gt;go&lt;/code&gt; thread.
This even works if we move the &lt;code&gt;&amp;lt;!!&lt;/code&gt; call out of the &lt;code&gt;binding&lt;/code&gt; form:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt; 1337] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core-async&lt;/span&gt; 42)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; {:headers &amp;#34;some: headers&amp;#34;, :body &amp;#34;42&amp;#34;, :token 1337}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, in &lt;code&gt;manifold&lt;/code&gt; I&amp;rsquo;d usually do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; you can use `bound-fn` here, and it will work without `let`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt; 1337] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold&lt;/span&gt; 42))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; {:headers &amp;#34;some: headers&amp;#34;, :body &amp;#34;42&amp;#34;, :token 1337}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now it&amp;rsquo;s working properly.
Or, if I have a more complex example, with functions generating functions and whatnot, I pass such bindings around as additional parameters, or as a table, if there are too many:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-token&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;token&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;binding &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*token*&lt;/span&gt; 1337] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;manifold&lt;/span&gt; 42))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; {:headers &amp;#34;some: headers&amp;#34;, :body &amp;#34;42&amp;#34;, :token 1337}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Though I could use &lt;code&gt;bound-fn&lt;/code&gt; here, for some reason it makes me worry about performance too much.
The point is &lt;code&gt;core.async&lt;/code&gt; properly captures bindings when it creates the &lt;code&gt;go&lt;/code&gt; block, so it&amp;rsquo;s less likely that you&amp;rsquo;ll get errors with it since you don&amp;rsquo;t have to remember to use &lt;code&gt;bound-fn&lt;/code&gt; or manually capture bindings with lexical scoping mechanisms.&lt;/p&gt;
&lt;h3 id=&#34;handling-errors&#34;&gt;Handling errors&lt;/h3&gt;
&lt;p&gt;Error handling in an asynchronous context is hard in general.
The approach each library takes is a bit different - &lt;code&gt;core.async&lt;/code&gt; is more barebones but can be managed, and &lt;code&gt;manifold&lt;/code&gt; can represent an error in the system pretty well.&lt;/p&gt;
&lt;p&gt;Unlike Clojure&amp;rsquo;s promises, deferreds in &lt;code&gt;manifold&lt;/code&gt; can store errors, and when you dereference such deferred, the error is being thrown:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Execution error (NullPointerException) at manifold.deferred/eval24263$chain (deferred.clj:838).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thus, you can use default &lt;code&gt;try&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; around points where your program becomes synchronous by explicitly awaiting a value.
Or, you can use &lt;code&gt;d/catch&lt;/code&gt; to catch errors in an asynchronous way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;java.lang.ArithmeticException&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deref&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This &lt;code&gt;d/catch&lt;/code&gt; function internally wraps the code into a &lt;code&gt;try&lt;/code&gt; block that catches exceptions and deals with them via deferreds.
You can specify what kind of exception you want to catch, just like you would do for a real &lt;code&gt;catch&lt;/code&gt; clause.
If the kind is unspecified, any &lt;code&gt;Throwable&lt;/code&gt; is caught, which is a bit broad, but there aren&amp;rsquo;t many options here sadly in the JVM.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;core.async&lt;/code&gt;, on the other hand, doesn&amp;rsquo;t have any mechanism for representing an error.
Channels can&amp;rsquo;t have &lt;code&gt;nil&lt;/code&gt; as a value, because receiving &lt;code&gt;nil&lt;/code&gt; from a channel means that the channel is closed.
So, if any kind of error happened in your asynchronous part of the code, you either have to pass it through our pipeline as an exception, or log the error and drop the data completely.
Some functions in the &lt;code&gt;core.async&lt;/code&gt; library take an additional exception handler.
The default handler simply logs the exception, which may not fly for your usecase.
Unlike &lt;code&gt;manifold&lt;/code&gt; however, you don&amp;rsquo;t need any fancy &lt;code&gt;catch&lt;/code&gt; replacements, you can just use plain &lt;code&gt;try&lt;/code&gt; in your &lt;code&gt;go&lt;/code&gt; blocks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;10 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;java.lang.ArithmeticException&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;error: %s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, the &lt;code&gt;go&lt;/code&gt; macro takes care of transforming this code into a meaningful state machine, that has error handling in the way you&amp;rsquo;d expect it to.&lt;/p&gt;
&lt;p&gt;It is possible, to define your own operations, like a throwing-take, that will throw when it receives an object that is an instance of &lt;code&gt;Throwable&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Throw an exception when the `port` returns an exception.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; ~&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;instance? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;java.lang.Throwable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v#&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v#&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;doto &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Exception.&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bang!&amp;#34;&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Exception&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-message&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;e&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints: bang!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can build your application with this kind of technique, but you need to make sure that all errors are fed back into channels, to be caught later, in order to establish a proper data flow.&lt;/p&gt;
&lt;h3 id=&#34;debugging-asynchronous-code&#34;&gt;Debugging asynchronous code&lt;/h3&gt;
&lt;p&gt;The last topic that I&amp;rsquo;d like to discuss in this section is debugging.
I use &lt;a href=&#34;https://cider.mx/&#34; target=&#34;_blank&#34;&gt;CIDER&lt;/a&gt;, which has an interactive step debugger, that I find quite helpful, and I use it &lt;strong&gt;a lot&lt;/strong&gt; when I want to understand what&amp;rsquo;s going on in some code that I didn&amp;rsquo;t write.
Debugger got me through a lot of times, and when it comes to debugging asynchronous code, &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt; are on the different ends of the spectrum.&lt;/p&gt;
&lt;p&gt;Because CIDER&amp;rsquo;s debugger instruments the code by injecting breakpoints into it, and then evals the form as usual, it&amp;rsquo;s not a problem for &lt;code&gt;manifold&lt;/code&gt; at all, because all functions, accepted by &lt;code&gt;chain&lt;/code&gt; are ordinary functions.
You can instrument them, redefine them, and even mock them via &lt;code&gt;with-redefs&lt;/code&gt; if you need to.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;go&lt;/code&gt; macro in the &lt;code&gt;core.async&lt;/code&gt; library, however, is not a good friend for debugging.
If you try to debug the function with a &lt;code&gt;go&lt;/code&gt; block in it, CIDER will throw an error, that can be quite hard to understand:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dbg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core-async&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server-async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:token&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*foo*&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2. Unhandled clojure.lang.Compiler$CompilerException
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Error compiling *cider-repl localhost:42295(clj)* at (1:8246)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   #:clojure.error{:phase :macro-syntax-check,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   :line 1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   :column 8246,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   :source
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &amp;#34;*cider-repl Git/async_vs_manifold:localhost:42295(clj)*&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   :symbol a/go}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             Compiler.java: 7027  clojure.lang.Compiler/macroexpand1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  meta.clj:  324  cider.nrepl.inlined.deps.orchard.v0v11v0.orchard.meta/macroexpand-all/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  meta.clj:  313  cider.nrepl.inlined.deps.orchard.v0v11v0.orchard.meta/macroexpand-all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               RestFn.java:  423  clojure.lang.RestFn/invoke
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  meta.clj:  319  cider.nrepl.inlined.deps.orchard.v0v11v0.orchard.meta/macroexpand-all/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  core.clj: 2772  clojure.core/map/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              LazySeq.java:   42  clojure.lang.LazySeq/sval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  walk.clj:   47  clojure.walk/walk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  meta.clj:  319  cider.nrepl.inlined.deps.orchard.v0v11v0.orchard.meta/macroexpand-all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  meta.clj:  313  cider.nrepl.inlined.deps.orchard.v0v11v0.orchard.meta/macroexpand-all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               RestFn.java:  423  clojure.lang.RestFn/invoke
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  meta.clj:  319  cider.nrepl.inlined.deps.orchard.v0v11v0.orchard.meta/macroexpand-all/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  core.clj: 2772  clojure.core/map/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              LazySeq.java:   42  clojure.lang.LazySeq/sval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  AFn.java:   22  clojure.lang.AFn/run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               session.clj:  218  nrepl.middleware.session/session-exec/main-loop/fn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               session.clj:  217  nrepl.middleware.session/session-exec/main-loop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  AFn.java:   22  clojure.lang.AFn/run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               Thread.java:  833  java.lang.Thread/run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1. Caused by clojure.lang.ExceptionInfo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Could not resolve var: data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   {:var data,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    :file &amp;#34;*cider-repl localhost:42295(clj)*&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    :column 28,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    :line 13}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Debugging &lt;code&gt;manifold&lt;/code&gt;&amp;rsquo;s chains, on the other hand, can be done without any issues.
That&amp;rsquo;s another downside of code transformation, instead of using proper support from the platform, but this is a downside the developers of &lt;code&gt;core.async&lt;/code&gt; are willing to take because supporting platforms without support for concurrency is more important here.&lt;/p&gt;
&lt;h2 id=&#34;mixing-core-dot-async-and-manifold&#34;&gt;Mixing &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;One of the goals of the &lt;code&gt;manifold&lt;/code&gt; project is to be general enough to be considered lingua franca and used as a translation layer when working with several different asynchronous libraries.
I once used both &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt; in the same project, because I wanted to use &lt;code&gt;core.async&lt;/code&gt; parallel pipelines, so I needed the data I provide to be stored in a channel.
It is definitively possible to mix and match both &lt;code&gt;go&lt;/code&gt; and &lt;code&gt;chain&lt;/code&gt; together, though the resulting code is a convoluted mess, so I&amp;rsquo;d suggest sticking to one library and not using both simultaneously as I did.
In short, I had a &lt;code&gt;go&lt;/code&gt; block which called a function that created a channel, then did a request to a socket server with the &lt;code&gt;aleph.tcp&lt;/code&gt; module, &lt;code&gt;manifold.deferred/chain&lt;/code&gt;&amp;lsquo;ed the result to a function that used &lt;code&gt;core.async/put!&lt;/code&gt; on the channel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; no real request, just an imitation here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/deferred&lt;/span&gt;) 100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some body&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;once: told me&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;communicate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-response&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead, what I could do was to use &lt;code&gt;manifold&lt;/code&gt; streams all the way through:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; no real request, just an imitation here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/timeout!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/deferred&lt;/span&gt;) 100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:body&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some body&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:headers&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;once: told me&amp;#34;&lt;/span&gt;}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;communicate&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/-&amp;gt;sink&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d/chain&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;send-to-server&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;req&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;resp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I only need to deal with a &lt;code&gt;manifold&lt;/code&gt; stream, representing a channel, and a deferred returned by the server.
The channel gets closed once we close the stream that was created from it, so for the outside world, it looks like this function was implemented with &lt;code&gt;core.async&lt;/code&gt;, even though technically it isn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;There are a lot of ways how we can create communication between the two libraries.
The example above creates a one-way port from &lt;code&gt;manifold&lt;/code&gt; side to &lt;code&gt;core.async&lt;/code&gt; side, but it&amp;rsquo;s often needed to communicate both ways.
To achieve that, &lt;code&gt;manifold&lt;/code&gt; provides spliced streams, which are constructed from a separate sink and a source.
This way you can do bidirectional communication between &lt;code&gt;core.async&lt;/code&gt; and &lt;code&gt;manifold&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;stream&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/splice&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/-&amp;gt;sink&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/-&amp;gt;source&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;port&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;stream&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;manifold took:&amp;#34;&lt;/span&gt; @(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/take!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s/put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; 28)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;core.async took:&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; prints:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; manifold took: 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; core.async took: 28&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are more ways of combining both libraries, which I&amp;rsquo;m not going to describe here, but the overall feeling is that &lt;code&gt;manifold&lt;/code&gt; has everything you&amp;rsquo;ll need to work seamlessly between the two.
Note, however, that this comes at a cost, and probably introduces intermediate buffers you don&amp;rsquo;t usually expect to have.&lt;/p&gt;
&lt;h2 id=&#34;my-personal-opinion-on-both-libraries&#34;&gt;My personal opinion on both libraries&lt;/h2&gt;
&lt;p&gt;The first library I used for asynchronous programming in Clojure, apart from agents, was &lt;code&gt;manifold&lt;/code&gt;, and I remember that it was hard for me to understand the code.
After some practice, I got the ropes of it, and it was pretty easy to think in terms of &lt;code&gt;chain&lt;/code&gt; and streams.
I&amp;rsquo;ve managed to write a lot of horribly complicated code with it, though.&lt;/p&gt;
&lt;p&gt;After that, I started looking at &lt;code&gt;core.async&lt;/code&gt; as a possible candidate to replace &lt;code&gt;manifold&lt;/code&gt; in our project.
It was much easier to understand, and honestly, I think that &lt;code&gt;go&lt;/code&gt; blocks lead to better code that has the benefit of being just like your ordinary Clojure code.&lt;/p&gt;
&lt;p&gt;However, I am a bit biased here, because I haven&amp;rsquo;t worked with asynchronous code before I saw &lt;code&gt;manifold&lt;/code&gt;, so since it was my first experience, and it wasn&amp;rsquo;t the most pleasant one, I may see &lt;code&gt;core.async&lt;/code&gt; as a better library sorely based on that impression.
I do like more the fact that in &lt;code&gt;core.async&lt;/code&gt; there&amp;rsquo;s only one concept of a channel, and everything nicely integrates with it.
You can use transducers with channels, you can wait for multiple channels at once, and cancel those that were too slow.
The fact that &lt;code&gt;core.async&lt;/code&gt; uses channels similarly to promises, by simply opening a channel, and closing it immediately after putting a single value onto it is an elegant solution for not having two asynchronous types, like in &lt;code&gt;manifold&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;manifold&lt;/code&gt; there are both deferreds and streams.
Deferreds can be successful or erroneous, so you have to be careful with them.
And streams can be sources, sinks, or both, and you sometimes have to check if something is a sink or not.
Sure, it provides more flexibility, but I enjoyed working with a more simple system more.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;code&gt;core.async&lt;/code&gt; is a thing in itself.
Once you&amp;rsquo;ve committed to using &lt;code&gt;core.async&lt;/code&gt; you can&amp;rsquo;t really interact with other things, like Java streams without defining your own wrappers.
The &lt;code&gt;manifold&lt;/code&gt; library has you covered.&lt;/p&gt;
&lt;p&gt;You can use default Clojure&amp;rsquo;s concurrency primitives, such as atoms or agents with both of these libraries, which I find great.
No need to limit yourself to only using channels/streams or deferreds, you can always call &lt;code&gt;swap!&lt;/code&gt; on an atom or &lt;code&gt;send&lt;/code&gt; a task to an agent if it makes sense.&lt;/p&gt;
&lt;p&gt;I think both &lt;code&gt;manifold&lt;/code&gt; and &lt;code&gt;core.async&lt;/code&gt; are great libraries, both having their upsides and downsides.
So use what fits the task you&amp;rsquo;re doing and don&amp;rsquo;t be afraid to experiment!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Not to be confused with an OS or JVM thread, or &lt;a href=&#34;https://clojure.github.io/core.async/#clojure.core.async/thread&#34; target=&#34;_blank&#34;&gt;clojure.core.async/thread&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Comparison of manifold and clojure.core.async&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 09 Jan 2023 22:58:00 +0300</pubDate>
    </item><item>
      <title>2022 Recap</title>
      <link>https://andreyor.st/posts/2022-12-30-recap/</link>
      <guid>https://andreyor.st/posts/2022-12-30-recap/</guid>
      <description>&lt;p&gt;Another year ends, so it&amp;rsquo;s time to gather my thoughts together and reflect on everything that happened this year.&lt;/p&gt;
&lt;p&gt;This was a decent year, despite all the bad things that have happened around the world.
And it was a very loud year too - one event after another without any breaks, all of which are covered in all of the media.
This ultimately made me stop using even more social platforms than before - I left Reddit and Twitter (this has nothing to do with Elon Musk), and cut the time I spend on YouTube in about half.
So as of today, I&amp;rsquo;m only available on &lt;code&gt;Git(?:La|Hu)b&lt;/code&gt;, Telegram, or via email.
And I consume news at my own pace via RSS only, and, honestly, this added a lot of free time to my schedule for reading books instead.&lt;/p&gt;
&lt;p&gt;Overall, I feel like I made decent progress this year.
I&amp;rsquo;ve worked on some topics that are new to me, like asynchronous programming, which resulted in making a library for Fennel, which turned out decent, I think.
I did almost a complete rewrite of my fennel-cljlib library, bringing more Clojure features into it, and used it in my other project Fenneldoc, which ended up in major refactoring.
Additionally, I made the ob-fennel project and did a rewrite of the REPL part in the fennel-mode package for Emacs.&lt;/p&gt;
&lt;p&gt;There was more fennel-related stuff this year, but I&amp;rsquo;d say that the novelty of the language wore off for me, and I&amp;rsquo;ve stepped aside a bit.
So I turned back to ClojureScript, and made a new demo page with it, featuring the Wave Function Collapse algorithm.
I also worked through the crafting interpreters book and made an implementation of the book&amp;rsquo;s language in Clojure.&lt;/p&gt;
&lt;p&gt;Later this year there was my first-ever participation in a game jam!
So I made a Brick Game with a twist in Fennel using the TIC80 fantasy computer.
It was fun, and I&amp;rsquo;m looking forward to participating again.&lt;/p&gt;
&lt;p&gt;Apart from actual programming, I started taking this blog a bit more seriously, I would say.
This year there are some articles that I&amp;rsquo;m kinda proud of, and I hope more to come.
I&amp;rsquo;m also continuing to develop as a speaker and giving three talks this year was far beyond my expectations.
I hope, the next year will not slow down in this regard.&lt;/p&gt;
&lt;p&gt;Last year&amp;rsquo;s recap mentioned that I would do things like that every year, but honestly, when it actually comes to it, I don&amp;rsquo;t know what to write about.
I don&amp;rsquo;t like repeating myself too often, so going back to stuff I did over the year, and already talked about, and talking about it again is not what I&amp;rsquo;d like to do, but I think it&amp;rsquo;s still beneficial to me, as I force myself to reflect on it.
So that&amp;rsquo;s that.&lt;/p&gt;
&lt;p&gt;Happy holidays and see you next year!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: 2022 Recap&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 30 Dec 2022 19:42:00 +0300</pubDate>
    </item><item>
      <title>Fixed version of pipeline-async and unordered pipeline variants</title>
      <link>https://andreyor.st/posts/2022-12-09-fixed-version-of-pipeline-async-and-unordered-pipeline-variants/</link>
      <guid>https://andreyor.st/posts/2022-12-09-fixed-version-of-pipeline-async-and-unordered-pipeline-variants/</guid>
      <description>&lt;p&gt;This is a follow-up to my previous post regarding the bug in the &lt;code&gt;clojure.core.async/pipeline-async&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;ve mentioned at the &lt;a href=&#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/#update&#34;&gt;end&lt;/a&gt; of that post, I&amp;rsquo;ve submitted a patch to &lt;a href=&#34;https://ask.clojure.org/index.php/12394/fix-for-the-async-163-off-by-two-error-in-pipeline-async&#34; target=&#34;_blank&#34;&gt;Ask Clojure&lt;/a&gt; that should fix the off by two error for the asynchronous pipeline.
It spawned some discussion, but as far as I can see, at least for now, there aren&amp;rsquo;t many chances for this issue to be fixed any time soon.&lt;/p&gt;
&lt;p&gt;Since I need this function at work, and I need to be able to fine-tune the number of tasks running simultaneously, I&amp;rsquo;ve put the fixed version into a library, for now.
This also should make it easier to test the function in the wild, as people don&amp;rsquo;t tend to patch libraries in Clojure, or in the JVM world in general.
The library source code is located at &lt;a href=&#34;https://github.com/andreyorst/pipeline-extras&#34; target=&#34;_blank&#34;&gt;GitHub&lt;/a&gt; and I&amp;rsquo;ve also submitted it to &lt;a href=&#34;https://clojars.org/io.github.andreyorst/pipeline-extras&#34; target=&#34;_blank&#34;&gt;Clojars&lt;/a&gt;.
Note, that the library doesn&amp;rsquo;t include &lt;code&gt;core.async&lt;/code&gt; as a dependency, so it is a requirement for your project to pull it.
The supplementary library should work on any version of the &lt;code&gt;core.async&lt;/code&gt; library, so I don&amp;rsquo;t want to force any version or update the library when &lt;code&gt;core.async&lt;/code&gt; updates.&lt;/p&gt;
&lt;p&gt;In addition to fixing the bug, I&amp;rsquo;ve also included a generalized unordered variant of the &lt;code&gt;pipeline*&lt;/code&gt; function, which is a basis for all other pipeline implementations.
I&amp;rsquo;ve &lt;a href=&#34;https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/#unordered-pipeline-async-implementation&#34;&gt;mentioned&lt;/a&gt; &lt;code&gt;pipeline-async-unordered&lt;/code&gt; in my previous post, and the main difference from the ordered one, apart from results coming in an arbitrary order, is higher throughput.
Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &amp;#39;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-extras.core&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &amp;#39;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core.async&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;1 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xf&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Thread/sleep&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;zero? &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 3)) 5000 100)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipeline&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p/pipeline-unordered&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xf&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3 4 5 6 7 8 9]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 10003.213591 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 1 4 5 7 8 3 6 9]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 5404.309124 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen here, in the &lt;code&gt;xf&lt;/code&gt; function every third element is processed longer than any other elements.
When we use &lt;code&gt;clojure.core.async/pipeline&lt;/code&gt; and measure the time it takes to process elements from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;9&lt;/code&gt;, it takes 10 seconds, because &lt;code&gt;pipeline&lt;/code&gt; waits before putting results, thus it can&amp;rsquo;t take any more data to process.
Because of that, every third element stops the conveyor.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pipeline-extras.core/pipeline-unordered&lt;/code&gt; on the other hand doesn&amp;rsquo;t care about the order, so it puts elements as they&amp;rsquo;re ready.
As can be seen, elements &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;6&lt;/code&gt;, and &lt;code&gt;9&lt;/code&gt; came last, because their processing took the longest time.
The total time needed to process the same amount of data is cut in half here, though it completely depends on the data order in this particular case.
E.g. if the first three elements were the longest to process, both functions would take the same time to finish.&lt;/p&gt;
&lt;p&gt;In general, the main difference two approaches is that in the unordered case, if one of the tasks is extremely slow, others can process data as usual.
In the ordered case if one of the tasks is extremely slow, others have to wait before putting data into the output channel, so the order is preserved.&lt;/p&gt;
&lt;p&gt;Hope this will be useful for someone, and if any problems arise, you can always file an issue at the project&amp;rsquo;s &lt;a href=&#34;https://github.com/andreyorst/pipeline-extras&#34; target=&#34;_blank&#34;&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Fixed version of pipeline-async and unordered pipeline variants&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 09 Dec 2022 22:41:00 +0300</pubDate>
    </item><item>
      <title>Clojure&#39;s core.async pipeline-async off-by-two error explained</title>
      <link>https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/</link>
      <guid>https://andreyor.st/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/</guid>
      <description>&lt;p&gt;Quite recently I&amp;rsquo;ve been working on my asynchronous programming library for Fennel, and fiddling with &lt;code&gt;clojure.core.async&lt;/code&gt; at the same time for my other project.
I&amp;rsquo;ve found an interesting function, called &lt;code&gt;pipeline-async&lt;/code&gt;, which seemed to be a good fit for my task.
Here&amp;rsquo;s the documentation for this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user&amp;gt; (doc clojure.core.async/pipeline-async)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clojure.core.async/pipeline-async
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([n to af from] [n to af from close?])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Takes elements from the from channel and supplies them to the to
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  channel, subject to the async function af, with parallelism n. af
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  must be a function of two arguments, the first an input value and
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  the second a channel on which to place the result(s). The
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  presumption is that af will return immediately, having launched some
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asynchronous operation whose completion/callback will put results on
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  the channel, then close! it. Outputs will be returned in order
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  relative to the inputs. By default, the to channel will be closed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  when the from channel closes, but can be determined by the close?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  parameter. Will stop consuming the from channel if the to channel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  closes. See also pipeline, pipeline-blocking.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the basic idea is that you can spawn &lt;code&gt;n&lt;/code&gt; asynchronous tasks that will be working in &lt;em&gt;parallel&lt;/em&gt; processing data from the &lt;code&gt;from&lt;/code&gt; channel, and putting results to the &lt;code&gt;to&lt;/code&gt; channel, in the order of the inputs.
The order here is important because that&amp;rsquo;s why this function behaves the way I&amp;rsquo;ll show later.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demonstration of this function processing data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &amp;#39;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core.async&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipeline-async&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 2017.977058 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3 4 5 6 7 8 9 10]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, I&amp;rsquo;ve created an &lt;code&gt;out&lt;/code&gt; channel, and a &lt;code&gt;data&lt;/code&gt; channel, containing numbers from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;9&lt;/code&gt;.
Then I&amp;rsquo;ve created a function &lt;code&gt;task&lt;/code&gt; that receives a &lt;code&gt;value&lt;/code&gt; and some &lt;code&gt;channel&lt;/code&gt;, sleeps for one second, and puts incremented value to that &lt;code&gt;channel&lt;/code&gt;, then closes it.
After that, I started the &lt;code&gt;pipeline-async&lt;/code&gt; with a parallelism of &lt;code&gt;3&lt;/code&gt; and our channels and the task as arguments.
And finally, we use &lt;code&gt;a/into&lt;/code&gt; to convert a channel to a vector, and await the operation with &lt;code&gt;a/&amp;lt;!!&lt;/code&gt;.
Kinda like &lt;code&gt;pmap&lt;/code&gt; on a limited thread pool, except we&amp;rsquo;re doing things in an asynchronous way here.&lt;/p&gt;
&lt;p&gt;So, as you can see, even though our asynchronous function sleeps for one second on each element, thanks to the parallelism of &lt;code&gt;3&lt;/code&gt; we&amp;rsquo;ve finished processing ten numbers in just two seconds!
Wait, I don&amp;rsquo;t think that math checks out&amp;hellip; shouldn&amp;rsquo;t it be close to four seconds instead?
I mean, &lt;code&gt;10&lt;/code&gt; divided by &lt;code&gt;3&lt;/code&gt; is not &lt;code&gt;2&lt;/code&gt;.
Let&amp;rsquo;s try with the parallelism of &lt;code&gt;1&lt;/code&gt; instead, it should be around ten seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipeline-async&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 4011.54529 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3 4 5 6 7 8 9 10]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait, now it looks like it has a parallelism of three!
Let&amp;rsquo;s add some logging:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;started job  &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;finished job &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipeline-async&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 4011.423488 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ho, now I see it, there&amp;rsquo;s an off-by-two error in &lt;code&gt;pipeline-async&lt;/code&gt;.
Instead of launching &lt;code&gt;1&lt;/code&gt; task, in this example &lt;code&gt;3&lt;/code&gt; tasks were launched!
That explains, why we see four seconds with parallelism of &lt;code&gt;1&lt;/code&gt; and only two seconds with parallelism of &lt;code&gt;3&lt;/code&gt; - in the latter case 5 tasks are running simultaneously.
And ten over five is indeed two.&lt;/p&gt;
&lt;h2 id=&#34;off-by-two-error&#34;&gt;Off-by-two error&lt;/h2&gt;
&lt;p&gt;Now, this is actually a &lt;a href=&#34;https://clojure.atlassian.net/browse/ASYNC-163&#34; target=&#34;_blank&#34;&gt;known bug&lt;/a&gt;, submitted to Clojure&amp;rsquo;s JIRA back in 2016.
However, it was closed with a &amp;ldquo;won&amp;rsquo;t fix&amp;rdquo; status, and I don&amp;rsquo;t think anyone is working on it.
I&amp;rsquo;ve studied the code of the &lt;code&gt;pipeline*&lt;/code&gt; function, which is a base for all &lt;code&gt;pipeline-*&lt;/code&gt; variants in &lt;code&gt;core.async&lt;/code&gt;, and couldn&amp;rsquo;t figure out why this happens just by looking at the code.&lt;/p&gt;
&lt;p&gt;So, I decided to port this function, to Fennel using channel implementation from my &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-async/&#34; target=&#34;_blank&#34;&gt;fennel-async&lt;/a&gt; library.
I did it, and as &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-async/-/blob/20620a40283c7139be173e08043b3f6188d93ff4/async.fnl#L948-982&#34; target=&#34;_blank&#34;&gt;can be seen&lt;/a&gt;, the comment in my implementation mentions the same &amp;ldquo;off-by-two&amp;rdquo; error.&lt;/p&gt;
&lt;p&gt;Because I got it as well.&lt;/p&gt;
&lt;p&gt;Somehow.&lt;/p&gt;
&lt;p&gt;Initially, I thought that my implementation may avoid this bug, because instead of callbacks I use Lua&amp;rsquo;s coroutines, to park threads, and a scheduler that runs through all asynchronous tasks in a loop.
However, as it turned out later, neither the channel implementation nor the core scheduling principles are strictly related to the problem.
It&amp;rsquo;s just how the code of &lt;code&gt;pipeline-async&lt;/code&gt; works.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the code for &lt;code&gt;pipeline*&lt;/code&gt; function, which is what &lt;code&gt;pipeline-async&lt;/code&gt; calls internally:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--pipeline-code&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-1&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-1&#34;&gt; 1&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-2&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-2&#34;&gt; 2&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-3&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-3&#34;&gt; 3&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-4&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-4&#34;&gt; 4&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-5&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-5&#34;&gt; 5&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-6&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-6&#34;&gt; 6&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-7&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-7&#34;&gt; 7&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-8&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-8&#34;&gt; 8&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-9&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-9&#34;&gt; 9&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-10&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-10&#34;&gt;10&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-11&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-11&#34;&gt;11&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-12&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-12&#34;&gt;12&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-13&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-13&#34;&gt;13&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-14&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-14&#34;&gt;14&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-15&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-15&#34;&gt;15&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-16&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-16&#34;&gt;16&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-17&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-17&#34;&gt;17&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-18&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-18&#34;&gt;18&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-19&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-19&#34;&gt;19&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-20&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-20&#34;&gt;20&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-21&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-21&#34;&gt;21&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-22&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-22&#34;&gt;22&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-23&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-23&#34;&gt;23&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-24&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-24&#34;&gt;24&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-25&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-25&#34;&gt;25&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-26&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-26&#34;&gt;26&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-27&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-27&#34;&gt;27&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-28&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-28&#34;&gt;28&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-29&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-29&#34;&gt;29&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-30&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-30&#34;&gt;30&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-31&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-31&#34;&gt;31&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-32&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-32&#34;&gt;32&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-33&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-33&#34;&gt;33&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-34&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-34&#34;&gt;34&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-35&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-35&#34;&gt;35&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-36&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-36&#34;&gt;36&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-37&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-37&#34;&gt;37&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-38&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-38&#34;&gt;38&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--e79458-39&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--e79458-39&#34;&gt;39&lt;/a&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-handler&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pos? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;]] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:blocking&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:compute&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;&lt;a href=&#34;#code-snippet--pipeline-code&#34;&gt;Code Snippet 1&lt;/a&gt;:&lt;/span&gt;
  &lt;code&gt;pipeline*&lt;/code&gt; source code
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;ve hidden some parts that are uninteresting to us (the &lt;code&gt;...&lt;/code&gt; markers) because this function can work in two ways - asynchronous and parallel.
We&amp;rsquo;re only interested in the asynchronous one, so the &lt;code&gt;process&lt;/code&gt; function is not interesting for our case, same for the &lt;code&gt;(:blocking :compute)&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;If called with the value of &lt;code&gt;n&lt;/code&gt; equal to &lt;code&gt;1&lt;/code&gt; this function spawns three &lt;code&gt;go-loop&lt;/code&gt; threads, which are asynchronous threads running on the &lt;code&gt;core.async&lt;/code&gt; thread pool.
These threads can be parked when needed, and are based on the callback system, this library implements.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to explain to you how &lt;code&gt;core.async&lt;/code&gt; works, because it is a huge topic, &lt;a href=&#34;https://www.youtube.com/watch?v=R3PZMIwXN_g&#34; target=&#34;_blank&#34;&gt;well covered&lt;/a&gt; by the author of the &lt;code&gt;go&lt;/code&gt; macro.
In short, each &lt;code&gt;&amp;lt;!&lt;/code&gt; in this code is a point of transformation, which turns all the code after the &lt;code&gt;&amp;lt;!&lt;/code&gt; call to a callback, attached to the channel of the &lt;code&gt;go&lt;/code&gt; block.
Maybe not exactly like that, but it&amp;rsquo;s beside the point, really.&lt;/p&gt;
&lt;p&gt;What you need to know about this function is, that at the very least it will spawn three internal &lt;em&gt;threads&lt;/em&gt;, and instinctively you might think that this is why there are three tasks running instead of one, as one would expect.
And you&amp;rsquo;re right, well, in a way, but not exactly.
It&amp;rsquo;s the interplay of these &lt;em&gt;threads&lt;/em&gt;, and the channels they use for synchronization that&amp;rsquo;s causing this.
Let me explain.&lt;/p&gt;
&lt;h2 id=&#34;explanation&#34;&gt;Explanation&lt;/h2&gt;
&lt;p&gt;So let&amp;rsquo;s try to understand why the off-by-two error happens in this code.
After reimplementing this function in Fennel, and spending a good amount of time thinking instead of sleeping, I think I got why it works the way it works.&lt;/p&gt;
&lt;p&gt;The main source of the issue is that this function wants to retain the order of outputs relative to inputs.
I don&amp;rsquo;t exactly know why this was a decision because when processing data, asynchronously transferring them between channels, I kinda expect the order to be mixed, because some tasks may take more time then others, but for some reason, this function was implemented specifically to prevent this from happening.
So, how it does it?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to refer to specific lines in the &lt;a href=&#34;#code-snippet--pipeline-code&#34;&gt;&lt;code&gt;pipeline*&lt;/code&gt; source code&lt;/a&gt; I&amp;rsquo;ve shown above, which is not equal to the original source, so keep that in mind.
Line numbers are links that should move your view to the mentioned line, but if you&amp;rsquo;re reading this on a big display, it&amp;rsquo;s better to open the code and the explanation side by side.
Sorry for the inconvenience.&lt;/p&gt;
&lt;p&gt;In lines &lt;a href=&#34;#org-coderef--e79458-5&#34;&gt;5&lt;/a&gt; and &lt;a href=&#34;#org-coderef--e79458-6&#34;&gt;6&lt;/a&gt; we create two channels &lt;code&gt;jobs&lt;/code&gt; and &lt;code&gt;results&lt;/code&gt;.
These channels are buffered with the same buffer size as our parallelism parameter &lt;code&gt;n&lt;/code&gt; and this is what should give us the back-pressure needed to achieve a limited amount of tasks running.
Then there are three &lt;code&gt;go-loop&lt;/code&gt; blocks defined at lines &lt;a href=&#34;#org-coderef--e79458-18&#34;&gt;18&lt;/a&gt;, &lt;a href=&#34;#org-coderef--e79458-22&#34;&gt;22&lt;/a&gt;, and &lt;a href=&#34;#org-coderef--e79458-30&#34;&gt;30&lt;/a&gt;.
I&amp;rsquo;ll call them &lt;code&gt;go-1&lt;/code&gt;, &lt;code&gt;go-2&lt;/code&gt;, and &lt;code&gt;go-3&lt;/code&gt; respectively.&lt;/p&gt;
&lt;p&gt;So, for the parallelism of &lt;code&gt;1&lt;/code&gt; the process goes like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-23&#34;&gt;go-2&lt;/a&gt; takes data from the &lt;code&gt;from&lt;/code&gt; channel.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-27&#34;&gt;go-2 puts the job&lt;/a&gt; to the &lt;code&gt;jobs&lt;/code&gt; channel, and a new channel to the &lt;code&gt;results&lt;/code&gt; channel in the next line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: full, &lt;code&gt;results&lt;/code&gt;: full&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-19&#34;&gt;go-1&lt;/a&gt; takes a &lt;code&gt;job&lt;/code&gt; from the &lt;code&gt;jobs&lt;/code&gt; channel, and spawns the asynchronous task at line &lt;a href=&#34;#org-coderef--e79458-12&#34;&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This task receives a value &lt;code&gt;v&lt;/code&gt; and a channel &lt;code&gt;res&lt;/code&gt;, to which it will put the result and &lt;code&gt;close!&lt;/code&gt; it.
This will be important for the &lt;code&gt;go-3&lt;/code&gt; channel later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-13&#34;&gt;go-1&lt;/a&gt; puts &lt;code&gt;res&lt;/code&gt; to the &lt;code&gt;p&lt;/code&gt; channel.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: empty, &lt;code&gt;results&lt;/code&gt;: full&lt;/p&gt;
&lt;ol start=&#34;5&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-31&#34;&gt;go-3 takes&lt;/a&gt; a value from the &lt;code&gt;results&lt;/code&gt; channel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-34&#34;&gt;go-3&lt;/a&gt; waits for the &lt;code&gt;p&lt;/code&gt; channel to get the &lt;code&gt;res&lt;/code&gt; channel from the step 3.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-36&#34;&gt;go-3&lt;/a&gt; waits for the asynchronous job to finish.&lt;/p&gt;
&lt;p&gt;This is when the asynchronous block started by the function we&amp;rsquo;ve passed as an argument to &lt;code&gt;pipeline-async&lt;/code&gt; is awaited.
Until it closes the &lt;code&gt;res&lt;/code&gt; channel, the &lt;code&gt;go-3&lt;/code&gt; thread will be parked.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: empty, &lt;code&gt;results&lt;/code&gt;: empty, &lt;code&gt;go-3&lt;/code&gt;: parked, one task is running.&lt;/p&gt;
&lt;ol start=&#34;8&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-23&#34;&gt;go-2&lt;/a&gt; takes data from the &lt;code&gt;from&lt;/code&gt; channel.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-27&#34;&gt;go-2 puts the job&lt;/a&gt; to the &lt;code&gt;jobs&lt;/code&gt; channel, and a new channel to the &lt;code&gt;results&lt;/code&gt; channel in the next line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: full, &lt;code&gt;results&lt;/code&gt;: full, &lt;code&gt;go-3&lt;/code&gt;: parked, one task is running.&lt;/p&gt;
&lt;ol start=&#34;10&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-19&#34;&gt;go-1&lt;/a&gt; takes a &lt;code&gt;job&lt;/code&gt; from the &lt;code&gt;jobs&lt;/code&gt; channel, and spawns the asynchronous task at line &lt;a href=&#34;#org-coderef--e79458-12&#34;&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is when the second task is spawned, despite the fact that the first one is still running.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-13&#34;&gt;go-1&lt;/a&gt; puts &lt;code&gt;res&lt;/code&gt; to the &lt;code&gt;p&lt;/code&gt; channel.&lt;/p&gt;
&lt;p&gt;This should advance &lt;code&gt;go-3&lt;/code&gt; block, but it is already parked.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: empty, &lt;code&gt;results&lt;/code&gt;: full, &lt;code&gt;go-3&lt;/code&gt;: parked, two tasks are running.
We&amp;rsquo;re still not done.&lt;/p&gt;
&lt;ol start=&#34;12&#34;&gt;
&lt;li&gt;&lt;code&gt;go-3&lt;/code&gt; is still parked, awaiting the first task.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-23&#34;&gt;go-2&lt;/a&gt; takes data from the &lt;code&gt;from&lt;/code&gt; channel yet again.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-27&#34;&gt;go-2 puts the job&lt;/a&gt; to the &lt;code&gt;jobs&lt;/code&gt; channel.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#org-coderef--e79458-28&#34;&gt;go-2 wants to put a new channel to the &lt;code&gt;results&lt;/code&gt; channel&lt;/a&gt; but the &lt;code&gt;results&lt;/code&gt; channel is full, so the &lt;code&gt;go-2&lt;/code&gt; parks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: full, &lt;code&gt;results&lt;/code&gt;: full, &lt;code&gt;go-3&lt;/code&gt;: parked, &lt;code&gt;go-2&lt;/code&gt;: parked, two tasks are running.&lt;/p&gt;
&lt;ol start=&#34;16&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-19&#34;&gt;go-1&lt;/a&gt; takes a &lt;code&gt;job&lt;/code&gt; from the &lt;code&gt;jobs&lt;/code&gt; channel, and spawns the asynchronous task at line &lt;a href=&#34;#org-coderef--e79458-12&#34;&gt;12&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is when the third task is spawned, despite the fact that the first one is still running.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;#org-coderef--e79458-13&#34;&gt;go-1&lt;/a&gt; puts &lt;code&gt;res&lt;/code&gt; to the &lt;code&gt;p&lt;/code&gt; channel.&lt;/p&gt;
&lt;p&gt;This should advance &lt;code&gt;go-3&lt;/code&gt; block, but it is already parked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;go-1&lt;/code&gt; wants to take a new &lt;code&gt;job&lt;/code&gt; from the &lt;code&gt;jobs&lt;/code&gt; channel, but the producer &lt;code&gt;go-2&lt;/code&gt; is parked, so &lt;code&gt;go-1&lt;/code&gt; parks as well.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current state&lt;/strong&gt;: &lt;code&gt;jobs&lt;/code&gt;: empty, &lt;code&gt;results&lt;/code&gt;: full, &lt;code&gt;go-3&lt;/code&gt;: parked, &lt;code&gt;go-2&lt;/code&gt;: parked, &lt;code&gt;go-1&lt;/code&gt;: parked, three tasks are running.&lt;/p&gt;
&lt;p&gt;Phew!
This is quite a convoluted process if you ask me!&lt;/p&gt;
&lt;p&gt;So the reason for the extra two jobs running is tied to the fact that between the &lt;code&gt;go-3&lt;/code&gt; thread parking, &lt;code&gt;go-2&lt;/code&gt; is able to push two more tasks before parking on &lt;code&gt;results&lt;/code&gt; channel being full.
I&amp;rsquo;m not sure if you&amp;rsquo;ve noticed this, but we can turn this off-by-two error into an off-by-one error simply by changing the order we put stuff to the &lt;code&gt;jobs&lt;/code&gt; and &lt;code&gt;results&lt;/code&gt; channel.&lt;/p&gt;
&lt;p&gt;So we simply need to change this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Into this:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--line-swap&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Now the whole process will park a bit earlier and only two tasks will run, as per the 10th step.
This doesn&amp;rsquo;t fix the error but makes it a bit more manageable, in cases when you&amp;rsquo;re not aware of the problem in the first place, and you&amp;rsquo;re trying to access a resource with a limited amount of connections.
Still can cause problems.&lt;/p&gt;
&lt;h2 id=&#34;unordered-pipeline-async-implementation&#34;&gt;Unordered &lt;code&gt;pipeline-async&lt;/code&gt; implementation&lt;/h2&gt;
&lt;p&gt;The issue can be fixed if we don&amp;rsquo;t maintain the order of results, and instead, put them by the order of task completion.
Here&amp;rsquo;s the implementation of such a function:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--pipeline-async-unordered&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-1&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-1&#34;&gt; 1&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-2&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-2&#34;&gt; 2&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-3&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-3&#34;&gt; 3&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-4&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-4&#34;&gt; 4&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-5&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-5&#34;&gt; 5&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-6&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-6&#34;&gt; 6&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-7&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-7&#34;&gt; 7&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-8&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-8&#34;&gt; 8&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-9&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-9&#34;&gt; 9&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-10&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-10&#34;&gt;10&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-11&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-11&#34;&gt;11&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-12&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-12&#34;&gt;12&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-13&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-13&#34;&gt;13&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-14&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-14&#34;&gt;14&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-15&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-15&#34;&gt;15&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-16&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-16&#34;&gt;16&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-17&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-17&#34;&gt;17&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-18&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-18&#34;&gt;18&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-19&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-19&#34;&gt;19&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-20&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-20&#34;&gt;20&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-21&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-21&#34;&gt;21&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-22&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-22&#34;&gt;22&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-23&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-23&#34;&gt;23&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-24&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-24&#34;&gt;24&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-25&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-25&#34;&gt;25&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-26&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-26&#34;&gt;26&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-27&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-27&#34;&gt;27&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-28&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-28&#34;&gt;28&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-29&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-29&#34;&gt;29&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-30&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-30&#34;&gt;30&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--1ed917-31&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--1ed917-31&#34;&gt;31&lt;/a&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async-unordered&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Takes elements from the from channel and supplies them to the to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  channel, subject to the async function af, with parallelism n. af
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  must be a function of two arguments, the first an input value and
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  the second a channel on which to place the result(s). The
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  presumption is that af will return immediately, having launched some
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  asynchronous operation whose completion/callback will put results on
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  the channel, then close! it. Outputs will be returned in order
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  of completion. By default, the to channel will be closed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  when the from channel closes, but can be determined by the close?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  parameter. Will stop consuming the from channel if the to channel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  closes. See also pipeline, pipeline-blocking.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async-unordered&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closes&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;repeat &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:close&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;closes&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;An interesting trick happens at line &lt;a href=&#34;#org-coderef--1ed917-16&#34;&gt;16&lt;/a&gt;.
We&amp;rsquo;re creating a channel that has &lt;code&gt;N-1&lt;/code&gt; elements in it.
Each thread when it is done processing all data and the &lt;code&gt;from&lt;/code&gt; channel was closed will &lt;a href=&#34;#org-coderef--1ed917-29&#34;&gt;try to take from that channel&lt;/a&gt;.
If the result is &lt;code&gt;nil&lt;/code&gt; it means other threads already exhausted the channel, and we&amp;rsquo;re the last one, and it is our responsibility to &lt;code&gt;close!&lt;/code&gt; the &lt;code&gt;to&lt;/code&gt; channel, if desired.&lt;/p&gt;
&lt;p&gt;The same example from above using this variant of &lt;code&gt;pipeline&lt;/code&gt; shows that there are exactly &lt;code&gt;3&lt;/code&gt; tasks running at a time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;started job  &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;finished job &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async-unordered&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 4007.215739 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 3 1 5 4 6 7 8 9 10]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, the order of elements is not the same as the order of inputs, but we get exactly three tasks running at a time.
This actually has another huge benefit over to default &lt;code&gt;pipeline-async&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You see, if the first-ever task in &lt;code&gt;pipeline-async&lt;/code&gt; takes the most amount of time to complete, this will be the time needed to get the first result from the &lt;code&gt;to&lt;/code&gt; channel.
Yes, other &lt;code&gt;N-1&lt;/code&gt; elements will be processed in parallel, however, until the first-ever task is finished, no more tasks will be taken &lt;strong&gt;at all&lt;/strong&gt;!
See for yourself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-1&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-1&#34;&gt; 1&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-2&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-2&#34;&gt; 2&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-3&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-3&#34;&gt; 3&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-4&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-4&#34;&gt; 4&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-5&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-5&#34;&gt; 5&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-6&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-6&#34;&gt; 6&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-7&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-7&#34;&gt; 7&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-8&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-8&#34;&gt; 8&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-9&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-9&#34;&gt; 9&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-10&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-10&#34;&gt;10&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-11&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-11&#34;&gt;11&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-12&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-12&#34;&gt;12&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-13&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-13&#34;&gt;13&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-14&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-14&#34;&gt;14&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-15&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-15&#34;&gt;15&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-16&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-16&#34;&gt;16&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-17&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-17&#34;&gt;17&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-18&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-18&#34;&gt;18&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-19&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-19&#34;&gt;19&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-20&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-20&#34;&gt;20&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-21&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-21&#34;&gt;21&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-22&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-22&#34;&gt;22&lt;/a&gt;
&lt;/span&gt;&lt;span style=&#34;white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34; id=&#34;org-coderef--649f86-23&#34;&gt;&lt;a style=&#34;outline: none; text-decoration:none; color:inherit&#34; href=&#34;#org-coderef--649f86-23&#34;&gt;23&lt;/a&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;started job  &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 10000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;finished job &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipeline-async&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 1 here is 3 actually&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 10013.587567 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In this example, I&amp;rsquo;ve made it so &lt;a href=&#34;#org-coderef--649f86-6&#34;&gt;only the first task&lt;/a&gt; will sleep for 10 seconds.
In the log, you can see that we&amp;rsquo;ve started three jobs (because of the off-by-two error), and then jobs &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; finished immediately.
Then we waited for job &lt;code&gt;0&lt;/code&gt; to finish before starting the job &lt;code&gt;3&lt;/code&gt;.
Thus the time for the first value to appear in the &lt;code&gt;out&lt;/code&gt; channel is 10 seconds.&lt;/p&gt;
&lt;p&gt;If we use &lt;code&gt;pipeline-async-unordered&lt;/code&gt; here, you can see that we have a much higher throughput:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;started job  &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 10000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;finished job &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async-unordered&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 4.602578 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, the first job to complete was the job &lt;code&gt;2&lt;/code&gt;, and then job &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, and long after that job &lt;code&gt;0&lt;/code&gt;.
If we change the example a bit and make other jobs sleep for, say 1 second, we&amp;rsquo;ll still get more throughput with an unordered version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;started job  &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 10000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;finished job &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/pipeline-async&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; 1 here is 3 actually&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 13011.037871 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 2 3 4 5 6 7 8 9 10]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here you can see that until we&amp;rsquo;ve finished the job &lt;code&gt;0&lt;/code&gt; we were waiting before we could take other jobs.
Because of that we first spent 10 seconds on the first three tasks, and then 3 seconds on the remaining task.
With the unordered version and the same parallelism, we spend at most 10 seconds, because other tasks can still run even though the first task is not completed yet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/to-chan!&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go&lt;/span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;started job  &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 10000))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/timeout&lt;/span&gt; 1000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;finished job &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/go-loop&lt;/span&gt; [] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log&lt;/span&gt;)] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async-unordered&lt;/span&gt; 3 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;time &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/&amp;lt;!!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;started&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;  9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finished&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 10003.531318 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 3 5 4 6 7 9 8 10 1]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I hope this gives a clear illustration of why you might want unordered version.&lt;/p&gt;
&lt;h2 id=&#34;a-possible-fix-for-pipeline-async&#34;&gt;A possible fix for &lt;code&gt;pipeline-async&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Apart from the already mentioned &lt;a href=&#34;#code-snippet--line-swap&#34;&gt;line swap&lt;/a&gt;, which turns this problem from off-by-two to off-by-one, I don&amp;rsquo;t think I can come up with any other ideas.
We kinda have to put channels to the &lt;code&gt;results&lt;/code&gt; channel, and then take them out, awaiting on the inner channel in order to preserve the order.
As a hack, we can subtract one from the number of threads we spawn in the &lt;code&gt;dotimes&lt;/code&gt; block, if &lt;code&gt;n&lt;/code&gt; is greater than &lt;code&gt;1&lt;/code&gt;, but this still leaves us with situations where two threads instead of one will run.
Disallowing parallelism of &lt;code&gt;1&lt;/code&gt; is an option too, as it doesn&amp;rsquo;t make any sense to use this function with such parallelism.
In other words:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;don&amp;#39;t use pipeline-async with parallelism of 1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline*&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;af&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should take care of most use cases, but isn&amp;rsquo;t a proper solution by any means.&lt;/p&gt;
&lt;p&gt;Given that I have the same problem in my &lt;code&gt;fennel-async&lt;/code&gt; library, I may eventually find the solution for it and propose it for the Clojure implementation too.
Unless it would use some Lua-specific features, that can&amp;rsquo;t easily be achieved without full coroutine support in the JVM, or other runtimes Clojure uses.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;Until then, I hope this was a useful and interesting read!&lt;/del&gt;&lt;/p&gt;
&lt;h2 id=&#34;a-proper-fix-for-pipeline-async&#34;&gt;A proper fix for &lt;code&gt;pipeline-async&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;After a bit more time, I think I figured out a proper way to fix the &lt;code&gt;pipeline-async&lt;/code&gt; function.
All we really need is a way to synchronize the channel that processes the result and the channel that processes the jobs.
We can add one more channel to the mix like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;diff&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;--git&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/src/main/clojure/clojure/core/async.clj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/src/main/clojure/clojure/core/async.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;index &lt;/span&gt;55&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ae450..66bfad0&lt;/span&gt; 100644
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;---&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/src/main/clojure/clojure/core/async.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+++&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b/src/main/clojure/clojure/core/async.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -530,6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+530&lt;/span&gt;,7 @@ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle.&#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finishes&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -540,7 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+541&lt;/span&gt;,9 @@ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle.&#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-removed&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;results&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finishes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt; 1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;put!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -554,6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+557&lt;/span&gt;,7 @@ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle.&#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:async&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;jobs&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;job&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;                                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finishes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go-loop&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -572,6 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+576&lt;/span&gt;,8 @@ &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handle.&#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finishes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;diff-added&#34; style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;finishes&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:done&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;todo - switch pipe arg order to match these (to/from)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This essentially means that the thread that spawns jobs will park until the thread that processes job results signals that the job is finished.
This way we basically ensure that there will be no more than &lt;code&gt;n&lt;/code&gt; active jobs.
I will look into the process of submitting this fix to the &lt;code&gt;core.async&lt;/code&gt; library soon.&lt;/p&gt;
&lt;div id=&#34;update&#34;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edit Nov 23 2022&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve submitted the patch from above as a Clojure Q&amp;amp;A question because it seems there&amp;rsquo;s no other way to suggest changes unless you&amp;rsquo;re a part of the Clojure development team who has access to the project&amp;rsquo;s JIRA.
The post is &lt;a href=&#34;https://ask.clojure.org/index.php/12394/fix-for-the-async-163-off-by-two-error-in-pipeline-async&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.
Alex Miller replied that they don&amp;rsquo;t think this is a problem that needs fixing, so I guess the bug is here to stay.&lt;/p&gt;
&lt;p&gt;It is interesting, however, that neither &lt;code&gt;pipeline&lt;/code&gt; or &lt;code&gt;pipeline-blocking&lt;/code&gt; share this behavior, as their implementation waits for the task result directly on the job consumer thread.
Which makes it more awkward to combine them with the asynchronous variant, when you need to have the same amount of threads.&lt;/p&gt;
&lt;p&gt;It is also a bit weird that all variants of &lt;code&gt;pipeline&lt;/code&gt; functions don&amp;rsquo;t return the out channel, so you can pass it through, and connect pipelines, so I end up using something like this when I need to mix pipelines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parallelism&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blocking-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data-ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out-ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-blocking&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parallelism&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out-ch&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blocking-fn&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data-ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out-ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-async&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parallelism&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data-ch&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assert &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parallelism&lt;/span&gt; 2)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; Compensate for the ASYNC-163&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out-ch&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;chan&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pipeline-async&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;parallelism&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out-ch&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;async-fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data-ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;out-ch&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Much like other Clojure functions that work with collections, these two accept the data channel as the last argument, so you can use the thread-last macro with them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;10)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to-chan!&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process&lt;/span&gt; 10 (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Thread/sleep&lt;/span&gt; 1000) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;process-async&lt;/span&gt; 10 (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;go&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;timeout&lt;/span&gt; 1000)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;v&lt;/span&gt;)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;close!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a/into&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;!!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Elapsed time: 2011.683893 msecs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 3 4 5 6 7 8 9 10 11]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This comes at a cost that you can&amp;rsquo;t use &lt;code&gt;pipeline-async&lt;/code&gt; with parallelism less than three, but it doesn&amp;rsquo;t make sense to do it anyway.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;Now, for real, thanks for reading!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Clojure&#39;s core.async pipeline-async off-by-two error explained&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 21 Nov 2022 09:47:00 +0300</pubDate>
    </item><item>
      <title>Revisiting your job pre-interview tasks is good for you</title>
      <link>https://andreyor.st/posts/2022-11-06-revisiting-your-job-interview-tasks-is-good-for-you/</link>
      <guid>https://andreyor.st/posts/2022-11-06-revisiting-your-job-interview-tasks-is-good-for-you/</guid>
      <description>&lt;p&gt;I have a somewhat weird tradition if it can be called like that - I&amp;rsquo;m revisiting job pre-interview tasks after a certain amount of time I&amp;rsquo;ve spent working in the company that gave the task.
It&amp;rsquo;s an interesting thing to do, and I think more people should do it on a more regular basis.
Let me try to convince you why.&lt;/p&gt;
&lt;p&gt;I got my first job as a programmer almost ten years ago, and I still remember my first-ever pre-interview task.
The task was, given a data sheet write a small program that will start the watchdog timer, and check if it counts in the right direction, e.g towards zero.
There was a small emulator I could use to test things, and basically, it was a task to find needed registers in the data sheet, write some specific values to them and see the results.
The thing is, even a such simple&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; task can be written in a lot of different ways.&lt;/p&gt;
&lt;p&gt;For example, the timer device is represented as an address in the memory, and you can simply calculate register addresses by a known offset.
Writing some &lt;code&gt;#define&lt;/code&gt; directives for each register is the one approach.
Another approach would be to write a timer as a &lt;code&gt;struct&lt;/code&gt; and define registers as fields of a specific size, allowing the compiler to calculate offsets for you, and providing a more object-like interface.
Or, you can just write everything without any defines or structures completely contained in the &lt;code&gt;main&lt;/code&gt; function without any kind of error handling, like I did the first time.&lt;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t familiar with bare-metal programming, it was my first-ever job, so I did my best to get it to work at the very least.
And I consider myself very lucky that this solution was accepted, and I am forever grateful that I was allowed to work there, and to all the wonderful people I met there, who taught me a lot.
This really kick-started my love for programming, and what made me where I am today.
If you&amp;rsquo;re reading this, &lt;strong&gt;thank you&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, after some years but during the time I still worked there, I found this timer task lying in my documents, and thought to myself that the code is so horrible, that I would never hire someone who could produce such an abomination.
At first, I was so disgusted with my own code that I thought that I&amp;rsquo;d just delete it and forget what I saw.
But then, later that day I calmed down and decided that I can&amp;rsquo;t go home without rewriting it.
I rewrote the code and went home with a lot of satisfaction because I literally saw all of my past mistakes, and applied all of my knowledge during the rewrite, producing clean and robust code.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve started doing it with all my pre-interview tasks from that moment on.
And I suggest you to do the same.&lt;/p&gt;
&lt;p&gt;However, recently I&amp;rsquo;ve expanded the idea a bit.
The last task was done in Clojure, and I wanted to try out new things I had no chance of using at work before.
So I sat down and picked a few libraries I thought were interesting to try and re-implemented the task from scratch under the same time constraints I had when I applied to the job.
This also brought up interesting emotions, because I know myself - I can tell for sure that back then, when I first wrote code for this pre-interview task, I couldn&amp;rsquo;t do the same thing, especially with unfamiliar tech.
But now I can, and it feels great.&lt;/p&gt;
&lt;p&gt;Today, I occasionally have to review this kind of tasks from candidates.
And every time I see some strange decisions, weird solutions, or silly mistakes, I remember my first iterations for such tasks and think to myself that this is fine, what matters the most is the people&amp;rsquo;s will to grow and learn.&lt;/p&gt;
&lt;p&gt;So, never stop learning, and try to reflect more often on how you&amp;rsquo;ve grown in the last few years!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=LKtk3HCgTa8&#34; target=&#34;_blank&#34;&gt;Simple, not easy&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Revisiting your job pre-interview tasks is good for you&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 06 Nov 2022 18:35:00 +0300</pubDate>
    </item><item>
      <title>Small languages with little tooling</title>
      <link>https://andreyor.st/posts/2022-11-02-small-languages-with-little-tooling/</link>
      <guid>https://andreyor.st/posts/2022-11-02-small-languages-with-little-tooling/</guid>
      <description>&lt;p&gt;When it comes to software I prefer things that are simple and small, even though I&amp;rsquo;m using Emacs.
This is mainly the reason why my favorite languages are Clojure and Fennel.
However, it doesn&amp;rsquo;t end on programming languages themselves, I like small tools in general.
One such example would be &lt;a href=&#34;https://kakoune.org/&#34; target=&#34;_blank&#34;&gt;Kakoune&lt;/a&gt; - a text editor, inspired by Vim, which focuses on multiple selections.&lt;/p&gt;
&lt;p&gt;Kakoune doesn&amp;rsquo;t have a scripting language, and when I started using it, the collection of plugins was relatively small, and it didn&amp;rsquo;t have a plugin manager at all.
With a limited amount of options, it&amp;rsquo;s easier to start using particular software, because you don&amp;rsquo;t have the problem of choice, especially when you know nothing about the things that you&amp;rsquo;re choosing from.
You pick it up, and you&amp;rsquo;re good to go.
This was a major problem for me to get into Emacs, as, as opposed to Kakoune, not only does it has a pretty huge core full of features, but it also has a ton of packages written by users over the years, and several package managers to install those.&lt;/p&gt;
&lt;p&gt;Eventually, I figured things out, and now I&amp;rsquo;m a happy Emacs user, but its enormous pack of inbuilt features still bothers me, and Kakoune made me understand why I like small ecosystems.
It&amp;rsquo;s because in a small ecosystem it&amp;rsquo;s easier to see what is needed by people, and you can participate in making things better not just for yourself but for everyone.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t quote me out on this, but I think &lt;a href=&#34;https://github.com/andreyorst/plug.kak&#34; target=&#34;_blank&#34;&gt;plug.kak&lt;/a&gt; was the first fully featured plugin and configuration manager for Kakoune, which I made mostly for myself, but to my surprise, it got to be pretty popular.
There even were plugins (written by other people) that suggested using &lt;code&gt;plug.kak&lt;/code&gt; as a preferred way of installing them.
Before &lt;code&gt;plug.kak&lt;/code&gt; people had to use the default mechanism of loading, which used an &lt;code&gt;autoload&lt;/code&gt; directory to specify what Kakoune should load at startup, and creating a such directory in your config disabled system-wide &lt;code&gt;autoload&lt;/code&gt; directory, making Kakoune featureless.
This was one of my motivations behind &lt;code&gt;plug.kak&lt;/code&gt;, because I saw issues in Kakoune&amp;rsquo;s repository titled mentioned that the creation of the &lt;code&gt;auotload&lt;/code&gt; dir broke their config in an unexpected way of not loading any of the inbuilt features.
My approach was to create a, hopefully, small system that knows where to look for external stuff and how to load and configure it.
And people seemed to like it.&lt;/p&gt;
&lt;p&gt;I also wrote a bunch of other plugins for Kakoune, all of which are listed &lt;a href=&#34;https://andreyor.st/about/#kakoune&#34;&gt;here&lt;/a&gt;, if you&amp;rsquo;re interested.
This helped me shape Kakoune into a thing that I liked to use, having features that I need, and also igniting my interest in programming in general, because the tools I built were used by other Kakoune users, and it was inspiring.
Later on alternatives to &lt;code&gt;plug.kak&lt;/code&gt; appeared, and I&amp;rsquo;m glad because they were simpler and more efficient.
I no longer maintain &lt;code&gt;plug.kak&lt;/code&gt;, as I no longer use Kakoune, but it still has a place in my heart.&lt;/p&gt;
&lt;p&gt;Before Kakoune I made plugins for Vim, but given that the plugin ecosystem was already saturated, my plugins were made mostly for myself and I wasn&amp;rsquo;t hoping that anybody else would prefer them to alternatives.
It was fun, still.&lt;/p&gt;
&lt;p&gt;So my point is - I like to participate in small ecosystems, mostly because the points where an improvement is welcome are more visible.
This leads us back to programming languages, and Fennel in particular.&lt;/p&gt;
&lt;h2 id=&#34;the-fennel-programming-language&#34;&gt;The Fennel Programming Language&lt;/h2&gt;
&lt;p&gt;If you read my blog, you may have seen posts about Fennel before, and likely know what it is.
If not, here&amp;rsquo;s a quick introduction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://fennel-lang.org&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; is a small surface language implemented on top of the Lua language.
It has a Clojure-inspired syntax, and Lisp macro system, allowing users to extend the language with new constructs pretty easily.
Fennel compiles down to Lua, and doesn&amp;rsquo;t have its own semantics, besides mentioned macro system and being a bit more strict.
And because Fennel is actually just a compiler, it includes almost no runtime features.
Its only runtime components are REPL (Read Eval Print Loop), which is a common thing for Lisps, and the pretty-printer - a small library that prints data structures in a way that can be read back by Fennel compiler, or just examined by us, humans.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve been using fennel for almost 2 years now, and I&amp;rsquo;ve been reflecting on what has changed for me personally.
What&amp;rsquo;s improved, what things I made for myself, and so forth.
And looking at my project workflow in Fennel, and seeing a lot of stuff happening, I get the impression of working in a mature language, with a mature ecosystem.
So I decided to write about this topic, highlighting interesting changes, that happened in the past two years of my Fennel experience.&lt;/p&gt;
&lt;h3 id=&#34;pretty-printer&#34;&gt;Pretty Printer&lt;/h3&gt;
&lt;p&gt;When I started using Fennel, the pretty-printer module was in a bit sad state.
It worked, but its output was not formatted as one would expect from a language with Clojure-like syntax.
Instead, it was formatted more like Lua code, and because of that, it was difficult to inspect deeply nested structures.&lt;/p&gt;
&lt;p&gt;I have a &lt;a href=&#34;https://andreyor.st/posts/2021-01-09-pretty-printing-for-fennel-language/&#34;&gt;post&lt;/a&gt; describing existing problems and my approach in detail, but in short, I had to rewrite the &lt;code&gt;fennelview.fnl&lt;/code&gt; module from the ground up.
And as far as I can tell, the community liked the new pretty printer, so the effort was well worth it.
It needed some tweaks here and there afterward made by other people, but I think this is still my biggest contribution to Fennel, especially since we&amp;rsquo;re seeing results of the pretty printer every time we send something to the REPL.
Which made Fennel much more pleasant to work with (for me, at least).&lt;/p&gt;
&lt;h3 id=&#34;the-fennel-cljlib-library&#34;&gt;The &lt;code&gt;fennel-cljlib&lt;/code&gt; library&lt;/h3&gt;
&lt;p&gt;With the pretty printer in place, I started working on various libraries that were just interesting to make.
The first one was &lt;a href=&#34;https://github.com/andreyorst/fennel-cljlib.git&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;, which was aimed at Clojure programmers that wanted to try out Fennel but didn&amp;rsquo;t want to give up some of the features they love in Clojure.
The library was crappy and had a lot of problems, which I fixed over the years, but right now I would say that it is solid.
Of course, there&amp;rsquo;s still a lot of room for improvement, but I&amp;rsquo;ve already utilized this library in some projects, and even seen its use in projects from other people!&lt;/p&gt;
&lt;p&gt;One thing that this library made me good at is writing macros.
Fennel has a similar syntax compared to Clojure, but it&amp;rsquo;s not the same, and some features are missing.
For instance, in Clojure, there is such thing as multi-arity functions, which are extremely handy.
Here&amp;rsquo;s how you might define such a function in Clojure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Sum arbitrary amount of numbers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([] 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rest&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So if you call this function with zero arguments given, the &lt;code&gt;([] 0)&lt;/code&gt; arity is selected, and &lt;code&gt;0&lt;/code&gt; is the return value.
If you call it with three arguments, the &lt;code&gt;([a b c] (+ a b c))&lt;/code&gt; branch is selected, and the return is the sum of three arguments.
However, if you call it with five-or-more arguments, the last arity &lt;code&gt;([a b c d &amp;amp; rest] (apply add (+ a b c d) rest))&lt;/code&gt; is selected, which will recursively call itself with less and fewer arguments, until it reaches another arity.
So the call stack is &lt;code&gt;(add 1 2 3 4 5 6 7 8 9 10)&lt;/code&gt; to &lt;code&gt;(add 10 5 6 7 8 9 10)&lt;/code&gt; followed by &lt;code&gt;(add 28 8 9 10)&lt;/code&gt; and the result value is &lt;code&gt;55&lt;/code&gt;.
That&amp;rsquo;s three tail-recursive calls, to sum 10 numbers, and we do as much work to avoid unnecessary recursive calls.&lt;/p&gt;
&lt;p&gt;Of course, math functions, such as this can be written in a more performant way without any recursion, this just illustrates the idea, that you can write functions in a pretty much declarative style: given this amount of arguments do this thing.
And with the &lt;code&gt;cljlib&lt;/code&gt; library we can define such functions
But I&amp;rsquo;ve lied to you, that&amp;rsquo;s actually not Clojure up there, but Fennel code, &lt;a href=&#34;https://github.com/andreyorst/fennel-cljlib/blob/e7951b59b9168fc57d83b6a0aaaf1c31d56cfa7f/init.fnl#L88-L95&#34; target=&#34;_blank&#34;&gt;defining one of the functions&lt;/a&gt; in &lt;code&gt;cljlib&lt;/code&gt;.
And if you scroll through the linked code, you&amp;rsquo;ll see that pretty much every function utilizes this feature of the language.
Even more so, if you take a look at Clojure sources, you&amp;rsquo;ll notice that a lot of code was ported almost directly, which some changes needed for it to work on the Lua runtime.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m going a bit off-topic here, this post is about the projects related to the language ecosystem, not just random projects of mine.
However, this library motivated me to make a contribution to the ecosystem, because I felt that there&amp;rsquo;s a point for improvement in the current workflow.
In the end, all I really want is a comfortable environment so I could enjoy programming a bit more, and maybe make it more enjoyable for other people as a side effect.
And I&amp;rsquo;m glad to see other people using the next project I&amp;rsquo;m going to talk about.&lt;/p&gt;
&lt;h3 id=&#34;fenneldoc&#34;&gt;Fenneldoc&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/andreyorst/fenneldoc.git&#34; target=&#34;_blank&#34;&gt;Fenneldoc&lt;/a&gt; is the tooling I wanted for Fennel so badly that I had to make one myself.&lt;/p&gt;
&lt;p&gt;This project is a rather simple documentation generation tool, which extracts documentation strings from functions&amp;rsquo; metadata, and creates a set of Markdown formatted files.
I wanted this tool because, already mentioned, &lt;code&gt;cljlib&lt;/code&gt; project had 60+ functions and 10+ macros, and I had to maintain documentation for all of that by hand.
And while I was working on this library and adding new functions, or changing existing ones, I had to keep the documentation in sync.
At some point, I was tired of noticing that I forgot to update some function&amp;rsquo;s documentation, or forgot to mention one entirely.
So I wrote &lt;code&gt;fenneldoc&lt;/code&gt; and &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib/-/commit/4ea70bf39971eeb742a5de689a9ad8ba63559ecb&#34; target=&#34;_blank&#34;&gt;replaced&lt;/a&gt;, all of the manually written documentation with auto-generated one.&lt;/p&gt;
&lt;p&gt;I &lt;strong&gt;know&lt;/strong&gt;, a lot of people seem to agree on the topic that auto-generated documentation is bad, however, I don&amp;rsquo;t think it&amp;rsquo;s entirely true.
There&amp;rsquo;s a popular post by Jacob Kaplan-Moss, which describes what to write in the documentation.
It has a paragraph regarding auto-generated documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don’t.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Auto-generated documentation is almost worthless.
At best it’s a slightly improved version of simply browsing through the source, but most of the time it’s easier just to read the source than to navigate the bullshit that these autodoc tools produce.
About the only thing auto-generated documentation is good for is filling printed pages when contracts dictate delivery of a certain number of pages of documentation.
I feel a particularly deep form of rage every time I click on a “documentation” link and see auto-generated documentation.&lt;/p&gt;
&lt;p&gt;There’s no substitute for documentation written, organized, and edited by hand.&lt;/p&gt;
&lt;p&gt;I’ll even go further and say that auto-generated documentation is worse than useless: it lets maintainers fool themselves into thinking they have documentation, thus putting off actually writing good reference by hand.
If you don’t have documentation just admit to it.
Maybe a volunteer will offer to write some!
But don’t lie and give me that auto-documentation crap.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;src-block-caption&#34;&gt;
&lt;a href=&#34;https://jacobian.org/2009/nov/10/what-to-write/&#34;&gt;Jacob Kaplan-Moss: Writing great documentation: What to write&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;m not sure exactly what kind of documentation here was in mind, and I can agree if we&amp;rsquo;re talking about documentation that was generated from the code alone.
I should also note that I have written a lot of documentation by hand before, and I would say that not all documentation is better when written like that.
And documentation can be hard to write in general, it certainly was for me.&lt;/p&gt;
&lt;p&gt;When working on a library, handwriting the documentation becomes very hard.
Not only do you have to sync every documentation entry with every update in your code base, but you&amp;rsquo;ll also have to remember what&amp;rsquo;s in the documentation and what&amp;rsquo;s missing.
And if you&amp;rsquo;re covering only the public API of your library it&amp;rsquo;s one thing, but when you also cover the private APIs for other developers to understand it&amp;rsquo;s a different kind of beast.
Doing all of this by hand can leave you no time to work on features as a result.&lt;/p&gt;
&lt;p&gt;The point is - it entirely depends on how documentation is generated, how it was written, and also for who you write it.
Your handwritten documentation may as well be complete garbage, useless for the end user if you have written it in a bad style or with a great lack of detail.
The same goes for auto-generated documentation - it &lt;em&gt;can&lt;/em&gt; be good, if the tooling is good, and if programmers took their time in writing meaningful things in the documentation strings/comments.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m getting a bit ranty here.&lt;/p&gt;
&lt;p&gt;So I think I found a compromise - I hand-write all documentation on a function level and generate the markdown files which enrich the documentation text with links between items automatically.
Paired with the fine-tuning of documentation order &lt;code&gt;fenneldoc&lt;/code&gt; provides, and the ability to add a general notice on top, it is possible to create documentation that reads as a normal document, yet is still usable when you found yourself in the sources.
And it is never out of date, unless you forgot to update it, which also happens without auto-generating.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s more.
What I also wanted from Fenneldoc was documentation testing.&lt;/p&gt;
&lt;p&gt;When I write documentation, I also include a lot of examples of how to use certain functions, or how they can be combined.
But after I change these functions, some examples might stop working.
And what&amp;rsquo;s good about having examples that don&amp;rsquo;t work when you try them?&lt;/p&gt;
&lt;p&gt;So Fenneldoc runs all examples and ensures that they at least compile.
You can include tests right into them, so they break when you&amp;rsquo;ve introduced an incompatible change and forgot to update the documentation.
It also checks if you&amp;rsquo;ve mentioned all of the function&amp;rsquo;s arguments in the documentation, and warns if it couldn&amp;rsquo;t find a cross-link to an item.&lt;/p&gt;
&lt;p&gt;For example, here&amp;rsquo;s another function from &lt;code&gt;cljlib&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;defn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;into&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Returns a new coll consisting of `to` with all of the items of `from`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;conjoined. A transducer `xform` may be supplied.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;# Examples
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Insert items of one collection into another collection:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```fennel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq [1 2 3 :a :b :c] (into [1 2 3] \&amp;#34;abcd\&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq {:a 2 :b 3} (into {:a 1} {:a 2 :b 3}))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Transform a hash-map into a sequence of key-value pairs:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;``` fennel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq [[:a 1]] (into (vector) {:a 1}))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;You can also construct a hash-map from a sequence of key-value pairs:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;``` fennel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;(assert-eq {:a 1 :b 2 :c 3}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;           (into (hash-map) [[:a 1] [:b 2] [:c 3]]))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;```&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vector&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/editable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;persistent!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/editable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;persistent!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see that it has a basic description of what it does, and a few examples of what happens when you use it.
Arguments to the function exist in the documentation, and they&amp;rsquo;re using a Markdown notation for monospaced text by being enclosed via the backticks, for instance, the &lt;code&gt;`xform`&lt;/code&gt; argument.
Here the documentation is just a string of Markdown formatted text in general.&lt;/p&gt;
&lt;p&gt;Below is the example section, which features code blocks denoted with the triple backticks, following a language name: &lt;code&gt;``` fennel ... ```&lt;/code&gt;.
In each example, there is a test, and you can see that all invocations are wrapped in &lt;code&gt;assert-eq&lt;/code&gt; calls, which is an assertion macro from my &lt;code&gt;fennel-test&lt;/code&gt; library.
In this particular example, I made a mistake and forgot to add the letter &lt;code&gt;d&lt;/code&gt; into the result of the very first call to &lt;code&gt;into&lt;/code&gt;.
When I try to export this documentation to Markdown, I get an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In file: &amp;#39;init.fnl&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Error in docstring for: &amp;#39;into&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;In test:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;``` fennel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(assert-eq [1 2 3 :a :b :c] (into [1 2 3] &amp;#34;abcd&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(assert-eq {:a 2 :b 3} (into {:a 1} {:a 2 :b 3}))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Error:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assertion failed for expression:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(eq [1 2 3 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34;] (into [1 2 3] &amp;#34;abcd&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Left: [1 2 3 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Right: [1 2 3 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34; &amp;#34;d&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The error message comes from the &lt;code&gt;assert-eq&lt;/code&gt; macro, which tests whether the &lt;em&gt;left&lt;/em&gt; expression is equal to the &lt;em&gt;right&lt;/em&gt; one.
Fenneldoc just makes it possible to see the test itself before it.
A simple test, but can catch some mistakes in the documentation!&lt;/p&gt;
&lt;p&gt;I find this tool quite usable and a big part of my project workflow - every project I do has documentation generated with Fenneldoc, and I even read it from time to time, despite the fact that I was the one writing it.&lt;/p&gt;
&lt;h3 id=&#34;fennel-test&#34;&gt;Fennel test&lt;/h3&gt;
&lt;p&gt;Speaking of testing, I also created a &lt;a href=&#34;https://github.com/andreyorst/fennel-test&#34; target=&#34;_blank&#34;&gt;fennel-test&lt;/a&gt; library because I didn&amp;rsquo;t like libraries aimed at testing Lua.
My library provides its own test runner, and tests are structured similarly to how they are in Clojure.
And if your project uses this library, it is possible to include it in the documentation testing pipeline as well, as I&amp;rsquo;ve shown before.&lt;/p&gt;
&lt;p&gt;Now, including huge tests in the documentation is really bad - in my opinion it should hold only small examples that also act as tests.
Also, I think that everything you write in the docstring should be displayed as is, so Fenneldoc doesn&amp;rsquo;t try to hide any stuff from the code blocks - the reader should see the whole picture.
The Rust programming language &lt;a href=&#34;https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#include-items-only-when-collecting-doctests&#34; target=&#34;_blank&#34;&gt;took a different approach&lt;/a&gt;, even has hidden documentation tests, that are there only when you test the documentation, not when you export it.
I don&amp;rsquo;t think this is the correct way, but the paragraph mentions that it has something to do with the internal limitations of their testing framework.&lt;/p&gt;
&lt;p&gt;So you should write tests that are a lot more complicated than your documentation tests, but since it is reserved for the test suite it&amp;rsquo;s not a problem.
Here&amp;rsquo;s the test for the &lt;code&gt;into&lt;/code&gt; function I&amp;rsquo;ve been talking about before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deftest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;test-into&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;testing&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;into&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; [1 2 3]) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.list&lt;/span&gt; 3 2 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [] []) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [1 2 3] []) [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [1 2 3] [4 5 6]) [1 2 3 4 5 6])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {} {}) {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1} {}) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1} {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2}) {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:a&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:b&lt;/span&gt; 2})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; [] {}) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; {} []) [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.vector&lt;/span&gt;) {})) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/type&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:vector&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assert-eq&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;getmetatable &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.into&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;core.hash-map&lt;/span&gt;) [])) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cljlib/type&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:hash-map&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ... more various cases ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, the &lt;code&gt;deftest&lt;/code&gt; is a macro, that defines the test function which is then executed by the test runner.
The runner can shuffle tests, capture errors, and form the log afterward.
I like how it works, and it&amp;rsquo;s fine for my use cases.
There also are other facilities, like fixtures, which you can use to wrap each test, or all of the tests with additional code, but they only work when using the test runner.&lt;/p&gt;
&lt;p&gt;OK, hopefully, this is all great and can help us write more understandable and maintainable programs in Fennel.
What about support from text editors then?&lt;/p&gt;
&lt;h3 id=&#34;editor-tooling&#34;&gt;Editor tooling&lt;/h3&gt;
&lt;p&gt;And text-editor support is another thing that often requires improvements when we&amp;rsquo;re dealing with young languages.
I&amp;rsquo;ve created Fennel syntax highlighting support for Kakoune, and I also currently maintain the &lt;code&gt;fennel-mode&lt;/code&gt; package for Emacs.
I know that Visual Studio Code has some support for Fennel, and NeoVim has great support with interactive features, and even the ability to configure the editor in Fennel itself.
Similarly to NeoVim, there&amp;rsquo;s also a text editor, called Lite, which is written in Lua, and there are projects that make it extendable via Fennel, which is great!
Still, Emacs as of this moment has the best Fennel support (IMO), as it has good support for Lisps in general.
However, there are always places to improve tooling, and I improved Fennel&amp;rsquo;s support in Emacs by providing automatic completions, documentation popups, and a scratch buffer for a different approach for interactive sessions.
I have some more plans on improving the REPL support and dynamic highlighting of loaded macro forms.&lt;/p&gt;
&lt;p&gt;In addition to that, I&amp;rsquo;ve made a small package to add support for Fennel to Org Mode, called &lt;a href=&#34;https://github.com/andreyorst?tab=repositories&#34; target=&#34;_blank&#34;&gt;ob-fennel&lt;/a&gt;.
I have an &lt;a href=&#34;https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/&#34;&gt;extensive post&lt;/a&gt; that goes into detail about how it can be used, so if you&amp;rsquo;re interested you can read it.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s an interesting project on the horizon: &lt;a href=&#34;https://git.sr.ht/~xerool/fennel-ls/&#34; target=&#34;_blank&#34;&gt;fennel-ls&lt;/a&gt; - a language server for Fennel.
A very welcome addition to the language ecosystem, and as far as I can tell after speaking with the author - a passionate project.
And, as far as I can see, every mature language eventually gets a language server, so this is a good sign!&lt;/p&gt;
&lt;h2 id=&#34;what-s-next&#34;&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s one point I want to replace in my current workflow with my Fennel project - coverage statistics.
Currently, I use the &lt;code&gt;luacov&lt;/code&gt; project, which analyzes Lua code specifically.
This is not a huge problem for me - I can read Lua, and I learned to read Lua that Fennel generates, but it is still a point of inconvenience.&lt;/p&gt;
&lt;p&gt;Ideally, I would like to have a tool similar to &lt;a href=&#34;https://github.com/cloverage/cloverage&#34; target=&#34;_blank&#34;&gt;cloverage&lt;/a&gt;, which is a Clojure library for generating code coverage reports.
I like it, because not only it works with Clojure code, and not some Java decompiled byte code, but it also shows coverage in terms of forms, not just lines.
For Fennel, it is a huge deal, because like in many lisps, forms may sit on a single line.
Though it is not a problem because I opt out of the &lt;code&gt;--correlate&lt;/code&gt; flag when I compile the project for coverage testing, so all one-liners are transformed into multiple lines, and I get pretty accurate coverage results.
Still inconvenient.&lt;/p&gt;
&lt;p&gt;But all of the above is only a small fraction of what has happened with Fennel overall - it&amp;rsquo;s just things that I&amp;rsquo;ve experienced in my project workflow.
There&amp;rsquo;s a lot of cool stuff happening even right now, and I welcome everybody to the upcoming &lt;a href=&#34;https://conf.fennel-lang.org/2022&#34; target=&#34;_blank&#34;&gt;FennelConf 2022&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From my point of view, Fennel grew a lot during the last two years.
We had the first major release and extended the language with new macros, and there are a lot of projects in the works regarding making the compiler more general via a plugin system.
I&amp;rsquo;m very excited about the future of Fennel and want to thank everybody in the community, which I&amp;rsquo;m glad I&amp;rsquo;m a part of.&lt;/p&gt;
&lt;p&gt;And I believe this situation is not unique to Fennel.
I know people who participate in other programming language-related communities, and I hear great things about them too.
Being in a small community is also beneficial in that you get to know a lot of people, and when someone new comes with some crazy ideas it&amp;rsquo;s always great to see what they can create with the project you are also passionate about.&lt;/p&gt;
&lt;p&gt;So keep hacking!
I&amp;rsquo;m looking forward to seeing more projects that help make developing ecosystem better, and I do my best for the ones I participate in!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Small languages with little tooling&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 02 Nov 2022 20:31:00 +0300</pubDate>
    </item><item>
      <title>Emacs Lisp shorthands as namespacing system</title>
      <link>https://andreyor.st/posts/2022-11-01-emacs-lisp-shorthands-as-namespacing-system/</link>
      <guid>https://andreyor.st/posts/2022-11-01-emacs-lisp-shorthands-as-namespacing-system/</guid>
      <description>&lt;p&gt;In Emacs version 28 Emacs developers introduced so-called read symbol shorthands.
If you&amp;rsquo;re interested in the rationale, feel free to search the Emacs developer mailing list for the discussion.
However, it does seem that not everyone likes the idea of shorthands as a substitution for namespaces (or packages, if you&amp;rsquo;re coming from Common Lisp).
Neither did I.
And recently, a &lt;a href=&#34;https://lists.gnu.org/archive/html/emacs-devel/2022-10/msg01654.html&#34; target=&#34;_blank&#34;&gt;branch was set up&lt;/a&gt; that implements Common Lisp-style packages for Emacs.
In the discussion Richard Stallman, however, notes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CL packages are the wrong way to implement packages in Lisp.
As I explained in a discussion two years ago, packages implemented using obarrays (or equivalent) don&amp;rsquo;t work reliably.&lt;/p&gt;
&lt;p&gt;We have a much better basis for Lisp packages in the shorthands mechanism.
It only needs to be completed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;src-block-caption&#34;&gt;
&lt;span&gt;Richard Stallman on &lt;/span&gt;&lt;a href=&#34;https://lists.gnu.org/archive/html/emacs-devel/2022-10/msg01786.html&#34;&gt;CL packages landed&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;ve read the discussion further and wanted to express some of my thoughts on the namespacing problem and how shorthands may help solve it in Emacs.&lt;/p&gt;
&lt;p&gt;While I&amp;rsquo;m not entirely sure how CL packages work underneath, I more or less know how namespaces in Clojure work (and to my knowledge these namespaces/package systems are quite similar), and I think that this is how I want namespaces to work in general.
As far as I can understand, Richard Stallman doesn&amp;rsquo;t like the idea of namespaces in general - he does mention it in some subsequent emails when he talks about obarrays.
Another quote from the mailing:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The reason namespaces systems do not fit well into Lisp is that they have to operate in &amp;lsquo;read&amp;rsquo;, in the choice of which symbol object you get.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;src-block-caption&#34;&gt;
&lt;span&gt;Richard Stallman on &lt;/span&gt;&lt;a href=&#34;https://lists.gnu.org/archive/html/emacs-devel/2016-10/msg00215.html&#34;&gt;Emacs Lisp&#39;s future&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Later on same message, he mentions that Clojure is not a Lisp, but we will not go there.&lt;/p&gt;
&lt;p&gt;Assuming the above, I guess &lt;code&gt;read-symbol-shorthands&lt;/code&gt; are going to be the way to do namespaces in Emacs in the future.
So let&amp;rsquo;s figure out how you actually use them and what they really do.&lt;/p&gt;
&lt;h2 id=&#34;read-symbol-shorthands&#34;&gt;&lt;code&gt;read-symbol-shorthands&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;According to the Emacs manual, shorthands are symbols renamed at read-time.
Because the shorthands are read-time, we need to set them in the local variables&amp;rsquo; section at the end of the file, which, as far as I understand, is processed before the &lt;code&gt;read&lt;/code&gt; step happens.
An example from the manual:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;snu-lines&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Split string  wholeS into a list of strings on newline characters.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;snu-split&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\\(\r\n\\|[\n\r]\\)&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Local Variables:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; read-symbol-shorthands: ((&amp;#34;snu-&amp;#34; . &amp;#34;some-nice-string-utils-&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; End:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the Emacs Lisp reader reads the name &lt;code&gt;snu-lines&lt;/code&gt; it will substitute the &lt;code&gt;snu-&lt;/code&gt; prefix with &lt;code&gt;some-nice-string-utils-&lt;/code&gt; and instead return the name &lt;code&gt;some-nice-string-utils-lines&lt;/code&gt; as if it was written like this.&lt;/p&gt;
&lt;p&gt;I guess this &lt;em&gt;kinda&lt;/em&gt; addresses one complaint I often hear about Emacs Lisp - you always have to write full symbol names.
And in Common Lisp or Clojure, you don&amp;rsquo;t need to do that, because the package/namespace system takes care of it.
I&amp;rsquo;m not really that good with CL, but Clojure has the same approach, so I&amp;rsquo;ll use it to demonstrate:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-nice-string-utils&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Split string `s` into a list of strings on newline characters.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.string/split-lines&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  I believe in Common Lisp this would be something like &lt;code&gt;cl-user:split-lines&lt;/code&gt;, if there was such a function there
&lt;/div&gt;
&lt;p&gt;This code defines the function &lt;code&gt;lines&lt;/code&gt; which can be used as &lt;code&gt;(lines &amp;quot;foo\nbar&amp;quot;)&lt;/code&gt; if you&amp;rsquo;re currently in the &lt;code&gt;some-nice-string-utils&lt;/code&gt; namespace.
If you&amp;rsquo;re in some other namespace, you have to use the full name: &lt;code&gt;(some-nice-string-utils/lines &amp;quot;foo\nbar&amp;quot;)&lt;/code&gt; (after you&amp;rsquo;ve required the namespace), or provide an explicit alias.&lt;/p&gt;
&lt;p&gt;So, similarly to Emacs Lisp, we can use the shortened name in the current file, but provide a less common name for the users.
And I can see how this can be seen as namespaces from Emacs standpoint, but it&amp;rsquo;s not that simple.&lt;/p&gt;
&lt;p&gt;My point here is that it&amp;rsquo;s not enough for Emacs package author to use &lt;em&gt;some&lt;/em&gt; prefix for their library - it would be better if it contained some author identification, so we could distinguish libraries that try to do similar things and share the name.
Instead, we get the situation where there can be only one &lt;code&gt;auto-complete.el&lt;/code&gt; package, despite the fact that &amp;ldquo;auto-complete&amp;rdquo; is a very generic way.
Other packages have to come up with different names, like &lt;code&gt;corfu&lt;/code&gt; or &lt;code&gt;company&lt;/code&gt;, because there&amp;rsquo;s no other way to distinguish packages other than by their name.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s have a look at how this is solved in other systems.&lt;/p&gt;
&lt;h2 id=&#34;namespaces-in-other-systems&#34;&gt;Namespaces in other systems&lt;/h2&gt;
&lt;p&gt;We, as programmers, live in quite big ecosystems, meaning we need ways to avoid confusion, and any programming language is one such ecosystem.
Once the popularity of a certain language grows to a certain point there is a possibility of name clashes - when someone made a function that is named exactly like yours but does an entirely different thing.
So language designers wanted to fix this problem, and a lot of languages have some notion of namespaces as a result.
I don&amp;rsquo;t really like Java, but I think it has a decent enough way of avoiding the problem of a name clash.&lt;/p&gt;
&lt;p&gt;Java libraries are written as packages that belong to a certain organization or individual, which is then used in the package name.
When you&amp;rsquo;re creating a library project, Java IDE will ask you about your organization, and the default value is &lt;code&gt;com.company&lt;/code&gt;.
And when I first saw this I didn&amp;rsquo;t understand why it is needed, but after some time it clicked on me.&lt;/p&gt;
&lt;p&gt;Even if some other company (or individual) will create a library that is named the same as mine, it will be still possible to distinguish them.
This works because Java widely uses the &lt;a href=&#34;https://en.wikipedia.org/wiki/Reverse_domain_name_notation&#34; target=&#34;_blank&#34;&gt;reverse domain grouping&lt;/a&gt; for their dependencies, and hence there&amp;rsquo;s very little possibility of a clash.
Library repositories, such as Maven then group artifacts by their group ID, which is exactly the &lt;code&gt;com.company&lt;/code&gt; thing, so it&amp;rsquo;s easy to distinguish libraries.&lt;/p&gt;
&lt;p&gt;So, for example, if I were to use this blog as a way to represent my identity in the Java libraries world, and I were to make the mentioned &lt;code&gt;some-nice-string-utils&lt;/code&gt; library, it would be used by others as &lt;code&gt;io.gitlab.andreyorst.some-nice-string-utils&lt;/code&gt;.
And if some other person wanted to make their own version of this library it could be &lt;code&gt;com.github.someuser.some-nice-string-utils&lt;/code&gt;, and everybody could still use it alongside mine without name clashes.&lt;/p&gt;
&lt;p&gt;This gives quite a long name to type, but the catch is that the user of the library doesn&amp;rsquo;t have to write full names, like &lt;code&gt;io.gitlab.andreyorst.some-nice-string-utils/lines&lt;/code&gt;.
They can import names directly into the current scope, and just use &lt;code&gt;lines&lt;/code&gt;, or define a shorthand, like &lt;code&gt;snu/lines&lt;/code&gt;, in case of Clojure.&lt;/p&gt;
&lt;p&gt;This still pollutes the global namespace of the runtime (kinda), it is just done in a much more controllable way, and possibilities of name clashing are minimized, and ways to recover from them are provided.
The renaming just doesn&amp;rsquo;t happen in read time, as in Emacs Lisp, but at load time, when the runtime modifies its global namespace registry to hold new namespaces.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another approach for namespacing, which is a bit simpler and doesn&amp;rsquo;t need a global namespace for packages at all.
Here&amp;rsquo;s what a typical Lua package looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt;(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; lines = {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; line &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; s:gmatch(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;([^&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;]+)&amp;#34;&lt;/span&gt;) &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    lines[#lines+1] = line
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; lines
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {lines=lines}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  some-nice-string-utils.lua
&lt;/div&gt;
&lt;p&gt;This file creates a function, which is only visible in this file, it doesn&amp;rsquo;t pollute the global namespace in any way.
Then at the end of the file, the table is returned, with one key &lt;code&gt;lines&lt;/code&gt; set to the definition of the function &lt;code&gt;lines&lt;/code&gt;.
So it is essentially a hash table object with one key representing the function name, and its value is the function object.&lt;/p&gt;
&lt;p&gt;You use this library in another file by simply requiring it into another local variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; snu = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;some-nice-string-utils&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(snu.lines(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;bar&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, the library is imported into a local variable, because the library is essentially just a hash table object, holding closures.
Then you index this hash table like &lt;code&gt;snu.lines&lt;/code&gt; which obtains the function object, which is then executed.&lt;/p&gt;
&lt;p&gt;It is a really simple system, that doesn&amp;rsquo;t require anything from the language except hash tables and first-class functions.
In fact, global scope in Lua is also just a table, named &lt;code&gt;_G&lt;/code&gt; - we could make it so that there&amp;rsquo;s no way to add stuff into it and the system would still work.
The beauty of it is that you can put your library file into a directory, like &lt;code&gt;my/snu.lua&lt;/code&gt; and require it as &lt;code&gt;require(&amp;quot;my.snu&amp;quot;)&lt;/code&gt;, and if someone else has the same named library it doesn&amp;rsquo;t matter, as the file system takes care of the problem already.
This comes with the overhead of the repeated table lookup, but you can always create another &lt;code&gt;local lines = snu.lines&lt;/code&gt; and use &lt;code&gt;lines&lt;/code&gt; without the additional lookup.
And LuaJIT actually optimizes repeated lookups away.&lt;/p&gt;
&lt;p&gt;Both systems solve the problem of the name clash, just a bit differently, and programmers can build their applications without worrying about overriding some other function.
But there&amp;rsquo;s still one more problem.&lt;/p&gt;
&lt;h2 id=&#34;library-versioning&#34;&gt;Library versioning&lt;/h2&gt;
&lt;p&gt;Neither Emacs Lisp approach to packages, nor Java&amp;rsquo;s approach to libraries really solve one problem - version clash.
Lua&amp;rsquo;s approach kinda allows you to manually solve it, as you can manually install a library into a versioned directory, and use both versions, but it requires some manual work.
You may wonder why would you want to use two versions of the same library, and while I agree that it is strange, it&amp;rsquo;s still not uncommon, because when you depend on several libraries, they also can have dependencies, and it is possible that they depend on the same thing but of different version.&lt;/p&gt;
&lt;p&gt;For example, let&amp;rsquo;s imagine that you have a project that depends on library A, and library B.
You describe it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;com.company.A&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; 1.1&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.0&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.gitlab.user.B&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; 2022-10-01&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-patch135&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These libraries are not connected to each other in any way whatsoever, but each of them specifies its own dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org.important.C&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; 1.0&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.0&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  library A dependencies
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:deps&lt;/span&gt; {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org.important.C&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:version&lt;/span&gt; 2.4&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.0&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 4:&lt;/span&gt;
  library B dependencies
&lt;/div&gt;
&lt;p&gt;This creates a situation when both libraries require one library C, but the versions are incompatible.
In your project you just use A and B and don&amp;rsquo;t even know about C, so here&amp;rsquo;s the question: what version of C you&amp;rsquo;ll get in your project after you&amp;rsquo;ve built it?&lt;/p&gt;
&lt;p&gt;The answer: it depends on the build system, language, alignment of the stars, and possibly other things.
Maven will likely pick the more recent version for you, other build tools may have other solutions.
Fennel, a language that compiles down to Lua, can include both dependencies, and it will work just fine without any clashes if you&amp;rsquo;ve used versioned paths in your &lt;code&gt;require&lt;/code&gt; calls.&lt;/p&gt;
&lt;p&gt;Clojure author Rich Hickey once said&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; that each major version of the library should just have a different artifact name, because if something broke it is a different thing now.&lt;/p&gt;
&lt;p&gt;I think that there may be other ways around this, not because that proposed way isn&amp;rsquo;t useful, but because we already have a version of the artifact, it&amp;rsquo;s there, we just need a system that respects it in the actual code.
Especially since Fennel already can do it.
File systems are great at this, in fact in Maven&amp;rsquo;s case, it is possible to have multiple versions of the same library available on the file system, it&amp;rsquo;s just the fact that most languages for some reason omit the version completely, and Java is no different.&lt;/p&gt;
&lt;p&gt;And Emacs&amp;rsquo; shorthand system actually allows us to do exactly this, even with the same artifact name.
So let&amp;rsquo;s get back to Emacs&amp;rsquo; side of things.&lt;/p&gt;
&lt;h2 id=&#34;shorthands-as-a-solution-to-both-name-and-version-clashing&#34;&gt;Shorthands as a solution to both name and version clashing&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create a library package that will be useless, but helps demonstrate the usefulness of shorthands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; foobar.el --- Useless library -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Author: Andrey Listopadov&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Homepage: https://gitlab.com/andreyorst/foobar.1.0.0.el&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Package-Requires: ((emacs &amp;#34;28.1&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Keywords: lisp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Prefix: foobar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Version: 1.0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; Commentary:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; no comments&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; Code:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foobar-foo&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foobar-bar&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;provide&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;foobar&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;;; foobar.el ends here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Local Variables:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; read-symbol-shorthands: ((&amp;#34;foobar&amp;#34; . &amp;#34;io.gitlab.andreyorst.foobar.1.0.0&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; End:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 5:&lt;/span&gt;
  foobar.el
&lt;/div&gt;
&lt;p&gt;We use a shorthand to transform our short package prefix into a versioned one with some author identity included.
To my knowledge, this should work absolutely fine - all &lt;code&gt;foobar&lt;/code&gt; entries are replaced with the &lt;code&gt;io.gitlab.andreyorst.foobar.1.0.0&lt;/code&gt;, even the at the &lt;code&gt;provide&lt;/code&gt; call end of the file.
Upon loading this file, Emacs has a feature, named &lt;code&gt;io.gitlab.andreyorst.foobar.1.0.0&lt;/code&gt;, and when we require it, it has two functions with the same prefix: &lt;code&gt;io.gitlab.andreyorst.foobar.1.0.0-foo&lt;/code&gt; and &lt;code&gt;io.gitlab.andreyorst.foobar.1.0.0-bar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s say we&amp;rsquo;ve introduced our breaking change, and removed the &lt;code&gt;foobar-bar&lt;/code&gt; function.
What should we do?&lt;/p&gt;
&lt;p&gt;We just change the shorthand to &lt;code&gt;io.gitlab.andreyorst.foobar.2.0.0&lt;/code&gt;, and the version header to &lt;code&gt;2.0.0&lt;/code&gt;.
That&amp;rsquo;s it, we can ship it.
How will it affect our users?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create two more packages that require our useless one (I&amp;rsquo;ll omit all stuff that is not necessary for this to &amp;ldquo;work&amp;rdquo; to keep it short):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Package-Requires: ((emacs &amp;#34;28.1&amp;#34;) (foobar &amp;#34;1.0.0&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;foobar&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; requires the &amp;#39;io.gitlab.andreyorst.foobar.1.0.0 feature&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-project-a-function&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foobar-bar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;provide&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;some-project-a&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Local Variables:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; read-symbol-shorthands: ((&amp;#34;foobar&amp;#34; . &amp;#34;io.gitlab.andreyorst.foobar.1.0.0&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; End:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 6:&lt;/span&gt;
  some-project-a.el
&lt;/div&gt;
&lt;p&gt;The first package pulls in our &lt;code&gt;foobar&lt;/code&gt; package of version &lt;code&gt;1.0.0&lt;/code&gt; as a dependency and uses its &lt;code&gt;foobar-bar&lt;/code&gt; function.
At the end of the file, we specify that &lt;code&gt;foobar-bar&lt;/code&gt; is actually &lt;code&gt;io.gitlab.andreyorst.foobar.1.0.0-bar&lt;/code&gt; and our &lt;code&gt;require&lt;/code&gt; also pulls in the correct feature (if the &lt;code&gt;foobar.el&lt;/code&gt; file was loaded).
Then there&amp;rsquo;s another package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Package-Requires: ((emacs &amp;#34;28.1&amp;#34;) (foobar &amp;#34;2.0.0&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;foobar&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; requires the &amp;#39;io.gitlab.andreyorst.foobar.2.0.0 feature&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-project-b-function&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foobar-foo&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;provide&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;some-project-b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Local Variables:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; read-symbol-shorthands: ((&amp;#34;foobar&amp;#34; . &amp;#34;io.gitlab.andreyorst.foobar.2.0.0&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; End:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 7:&lt;/span&gt;
  some-project-b.el
&lt;/div&gt;
&lt;p&gt;Again, we pull in &lt;code&gt;foobar&lt;/code&gt; as a dependency, but we use the &lt;code&gt;2.0.0&lt;/code&gt; version.
As you may remember, there&amp;rsquo;s no function &lt;code&gt;foobar-bar&lt;/code&gt; in this version, but there&amp;rsquo;s still &lt;code&gt;foobar-foo&lt;/code&gt;, and that&amp;rsquo;s what this package uses.
And we know that it uses the correct one, because again at the end of the file, we specify that &lt;code&gt;foobar&lt;/code&gt; is actually &lt;code&gt;io.gitlab.andreyorst.foobar.2.0.0&lt;/code&gt;, and our &lt;code&gt;require&lt;/code&gt; also pulls in the correct feature.&lt;/p&gt;
&lt;p&gt;Both packages are not affected at all, because each still uses a different feature.
And both features can co-exist, without any name clashes.&lt;/p&gt;
&lt;p&gt;Problem solved, right?&lt;/p&gt;
&lt;h2 id=&#34;problems&#34;&gt;Problems&lt;/h2&gt;
&lt;p&gt;There are, of course, some problems with this approach.&lt;/p&gt;
&lt;p&gt;The first one is that we&amp;rsquo;re replacing a common prefix, that doesn&amp;rsquo;t end on a &lt;code&gt;-&lt;/code&gt; symbol, so if any of the projects using our library had defined something like &lt;code&gt;foobarbaz&lt;/code&gt; it may be a source of errors.
In a language with proper namespaces, defining something outside the current namespace, which is what essentially happens here, is either impossible or a compile-time error.&lt;/p&gt;
&lt;p&gt;While this can be ignored in most cases, if the project uses a multi-file approach, it may cause problems that shorthands exist for one file, and it replaces &lt;code&gt;foobarbaz&lt;/code&gt; with some other name &lt;code&gt;foobar-expanded-shorthand-baz&lt;/code&gt;.
And if another file, that requires the previous one, doesn&amp;rsquo;t have the same shorthand, it may search for &lt;code&gt;foobarbaz&lt;/code&gt; and be unable to find it.
Multi-file dependencies also have to maintain the same shorthands for all files they require internally, which can be a burden.&lt;/p&gt;
&lt;p&gt;Another problem is that we have to maintain the package version in two separate places - one in the package header, and another in the shorthand.
And we &lt;strong&gt;have&lt;/strong&gt; to keep the version in the shorthand, to allow several versions of the same feature to coexist.
Which is crucial in a system such as Emacs, where there are tons of old or not-maintained packages, which require older dependencies, many of which were already updated in an incompatible way, and there&amp;rsquo;s a possibility of another package requiring newer version.&lt;/p&gt;
&lt;p&gt;This can lead to problems when the package is large enough not to fit on the screen, and the contributor fixes some bug in one of the functions, and updates the header, but is completely unaware that there&amp;rsquo;s a shorthand defined down below.
Tests will not be able to catch this unless things like &lt;code&gt;flymake&lt;/code&gt; will learn to detect versioned shorthands.
And while this problem may seem strange to mention - we&amp;rsquo;re all people, so I can easily see it happening.&lt;/p&gt;
&lt;p&gt;Yet another thing to remember is that the order of shorthands is important.
You should position more specific shorthands first, and less specific last.
For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a-foo&lt;/span&gt; 42)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a-b-bar&lt;/span&gt; 1337)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Local Variables:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; read-symbol-shorthands: ((&amp;#34;a-&amp;#34; . &amp;#34;less-specific-&amp;#34;) (&amp;#34;a-b-&amp;#34; . &amp;#34;more-specific-&amp;#34;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; End:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, both vars will transform to &lt;code&gt;less-specific-foo&lt;/code&gt; and &lt;code&gt;less-specific-b-bar&lt;/code&gt;.
Changing &lt;code&gt;read-symbol-shorthands&lt;/code&gt; to &lt;code&gt;((&amp;quot;a-b-&amp;quot; . &amp;quot;more-specific-&amp;quot;) (&amp;quot;a-&amp;quot; . &amp;quot;less-specific-&amp;quot;))&lt;/code&gt; will produce &lt;code&gt;less-specific-foo&lt;/code&gt; and &lt;code&gt;more-specific-bar&lt;/code&gt;.
Perhaps, Emacs could sort shorthands in such a way that more specific ones come first, but this may have unexpected effects from the user&amp;rsquo;s perspective.
With a more advanced namespace system, this won&amp;rsquo;t be an issue at all.&lt;/p&gt;
&lt;p&gt;And a final problem - package managers.
Emacs&amp;rsquo; builtin package manager &lt;code&gt;package.el&lt;/code&gt; can work with this kind of system because when you install a package, it ends up in a versioned directory, e.g. &lt;code&gt;&amp;lt;user-emacs-directory&amp;gt;/elpa/&amp;lt;package&amp;gt;-&amp;lt;version&amp;gt;/package.el&lt;/code&gt;.
So in this case, when we&amp;rsquo;re updating a such package, it will be installed with no problem, and packages that require it via shorthand will still work.&lt;/p&gt;
&lt;p&gt;However, there are such package managers as &lt;code&gt;straight.el&lt;/code&gt; which work by pulling packages from git repositories, and as far as I know, straight doesn&amp;rsquo;t support package versioning.
There are other package managers, like &lt;code&gt;borg&lt;/code&gt;, &lt;code&gt;elget&lt;/code&gt;, etc. which I&amp;rsquo;m not familiar with, maybe they support versioning, maybe not - it is a thing to be concerned about when suggesting symbol shorthands as a namespace alternative.&lt;/p&gt;
&lt;p&gt;Finally, though, not really a problem, but it is still a concerning point - older Emacs releases don&amp;rsquo;t support shorthands.
If I were to adopt the scheme I&amp;rsquo;ve described above for my packages, I would have to abandon users of anything below Emacs 28.
According to the unofficial Emacs survey, in the year 2020 57% of participants used Emacs 27, and another 20% were on Emacs 26, so I imagine that there will be users who don&amp;rsquo;t have shorthands for a couple of years.&lt;/p&gt;
&lt;p&gt;All of this can be fixed though.&lt;/p&gt;
&lt;h2 id=&#34;so-why-we-don-t-like-shorthands-again&#34;&gt;So why we don&amp;rsquo;t like shorthands again?&lt;/h2&gt;
&lt;p&gt;When I was talking about our three packages in Emacs Lisp, I had to write all names starting with a &lt;em&gt;unique&lt;/em&gt; prefix that then can be distinguished by the reader.
And I believe this is the main problem here - usually, we don&amp;rsquo;t want to write the full, versioned name of the feature for each function or var, yet we want them to stay unique, and reader shorthands are a hacky way to achieve that.
The key word here is &lt;em&gt;hacky&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It requires the programmer to create and manage shorthands in a special comment section instead of providing a way of doing it with regular code.
In my opinion, we could still do things read time, but give it a more general interface, instead of just the text substitution, and that is what actually leads us to CL-style packages or Clojure-like namespace systems.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure if it is possible in Emacs Lisp, but if we could define a special that would affect the reader, similarly to how the &lt;code&gt;read-symbol-shorthands&lt;/code&gt; setting in the local variables comment does, we could have a system pretty close to CL ones.
E.g. the reader could automatically prepend package name while reading code, especially the definitions like &lt;code&gt;defun&lt;/code&gt; or &lt;code&gt;defvar&lt;/code&gt;, we could have this done automatically without any prefixes.
And when reading a free symbol&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, automatically intern it in the current package, by prepending a package name while reading its name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;io.gitlab.andreyorst.foobar.3.0.0&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; configure reader at the top of the file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; ()          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; reads (defun io.gitlab.andreyorst.foobar.3.0.0:lines ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;some-other-fn&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; reads&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (defun io.gitlab.andreyorst.foobar.3.0.0:some-other-fn ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; 1 2 3)           &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; reads (emacs.28.c-core:list 1 2 3)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; because there was no definition of the list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; in this package, and no prefix is used&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lines&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;)              &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; reads&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (io.gitlab.andreyorst.foobar.3.0.0:lines s)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; because its already interned&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And when the library requires such a package, we could again set up the reader with a special syntax to do the shorthands stuff:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;require-package&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.gitlab.andreyorst.foobar.3.0.0&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fb&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fb:lines&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt;)  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; reads (io.gitlab.andreyorst.foobar.3.0.0:lines &amp;#34;...&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; because of the configured prefix alias&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where require-package is another special, that sets up shorthands for the reader, and expands to actual &lt;code&gt;require&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;This is just a quick draft of what it could have looked like if instead of a comment we could deal with a new small set of specials that did the setup for us based on what we actually require or provide.
Again, Richard Stallman considers the Common Lisp style package system broken, maybe the automatic interning is one of the unknown symbols one of the reasons, I don&amp;rsquo;t know, but this is still pretty much the same implementation as with the shorthands.
It is just more automated.&lt;/p&gt;
&lt;h2 id=&#34;alternatives&#34;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;In the already mentioned &lt;a href=&#34;https://www.youtube.com/watch?v=oyLBGkS5ICk&#34; target=&#34;_blank&#34;&gt;Spec-ulation Keynote&lt;/a&gt; talk, Rich Hickey gave, he mentions that actual dependencies are not artifacts but &lt;a href=&#34;https://www.youtube.com/watch?v=oyLBGkS5ICk&amp;amp;t=646s&#34; target=&#34;_blank&#34;&gt;the code itself&lt;/a&gt;.
Names, if you will.
If a function &lt;code&gt;A/foo&lt;/code&gt; only needs &lt;code&gt;B/bar&lt;/code&gt; function, and in our project, we only use the function &lt;code&gt;A/foo&lt;/code&gt;, our dependencies are not &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, our dependencies are &lt;code&gt;A/foo&lt;/code&gt; and &lt;code&gt;B/foo&lt;/code&gt;.
It&amp;rsquo;s just the fact that our packaging systems require us to pull all code from the library, not just definitions.
Of course, there are languages that do tree shaking, excluding unused code from the final application build, but this doesn&amp;rsquo;t affect our dependencies - we still pull libraries as a whole.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s an interesting language, called &lt;a href=&#34;https://www.unison-lang.org/&#34; target=&#34;_blank&#34;&gt;Unison&lt;/a&gt;.
It is quite different from other languages because they implemented the idea of code-level dependencies:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s the big idea behind Unison, which we&amp;rsquo;ll explain along with some of its benefits:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Each Unison definition is identified by &lt;strong&gt;a hash of its syntax tree&lt;/strong&gt;.
Put another way, Unison code is content-addressed.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This essentially means that each definition has a unique ID, so if you depend on some definition you can refer to its hash to obtain the exact thing you&amp;rsquo;re dependent on.
It also means that there&amp;rsquo;s no need for namespaces at all.
If you have written a definition that does one thing, it will have a unique hash, which the rest of the world will use to refer to your definition - it will never collide.
You can give it an appropriate and descriptive name in &lt;strong&gt;your&lt;/strong&gt; program, but this name will never affect other people&amp;rsquo;s code.&lt;/p&gt;
&lt;p&gt;Emacs is way beyond the point where such a system could be introduced, but I think it is still worth mentioning it.&lt;/p&gt;
&lt;h2 id=&#34;can-shorthands-be-used-as-a-namespacing-system&#34;&gt;Can shorthands be used as a namespacing system?&lt;/h2&gt;
&lt;p&gt;So this is the main question I wanted to answer here.&lt;/p&gt;
&lt;p&gt;I think yes, symbol shorthands can be used for namespacing, and if used properly, they can also solve versioning problems, at least to some degree.
However, this is really a poor man&amp;rsquo;s namespacing system, as in reality, it&amp;rsquo;s just a text substitution, and we&amp;rsquo;re still acting in one giant global namespace, it&amp;rsquo;s just the fact that the name clash is made harder.&lt;/p&gt;
&lt;p&gt;A key point of namespacing systems is to be able to reuse the same name across different namespaces, and that&amp;rsquo;s what shorthands in their current form don&amp;rsquo;t provide at all.
Using a short enough prefix is a workaround, though.&lt;/p&gt;
&lt;p&gt;As much as I would like to have a better system, I guess I&amp;rsquo;ll have to stick to what Emacs developers decide to use in the future.
Richard Stallman mentions that &amp;ldquo;It only needs to be completed&amp;rdquo;, so I guess we will see the improvements in the future.
But again, it may actually delay the ability to actually use these namespaces for another few years from that point.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=oyLBGkS5ICk&amp;amp;t=1793s&#34; target=&#34;_blank&#34;&gt;Spec-ulation Keynote (29:53)&lt;/a&gt;
I highly recommend watching this talk as a whole, as it raises a lot of points about versioning changes.
In addition, this talk has a much more comprehensive description of the problem I&amp;rsquo;m touching here.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I can see how this may be problematic at read-time, but we can assume that everything undefined or without a prefix, or not required with an explicit alias is a free symbol.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Emacs Lisp shorthands as namespacing system&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 01 Nov 2022 18:17:00 +0300</pubDate>
    </item><item>
      <title>My blogging setup with Emacs and Org Mode</title>
      <link>https://andreyor.st/posts/2022-10-16-my-blogging-setup-with-emacs-and-org-mode/</link>
      <guid>https://andreyor.st/posts/2022-10-16-my-blogging-setup-with-emacs-and-org-mode/</guid>
      <description>&lt;p&gt;&lt;em&gt;Or &amp;ldquo;when you don&amp;rsquo;t have topics to write about, write about how you do your writing&amp;rdquo;.&lt;/em&gt;
Ahem.&lt;/p&gt;
&lt;p&gt;I like my blog workflow, it makes me want to return to writing more often, and because of this, I capture way more thoughts than I would usually do if I didn&amp;rsquo;t have a blog.
However, there are a lot of ways to set up a blog, and when I was starting I was overwhelmed with options.
There are a lot of posts with the title &amp;ldquo;my blogging setup with&amp;hellip;&amp;rdquo; and most of these that I&amp;rsquo;ve seen are very shallow in detail.
With this post, I would hope to explain things in a bit more detail, so people who&amp;rsquo;re interested in creating their own blog could use this post as an instruction, sort of.
Or maybe it will be yet another post that will not be that helpful to anyone struggling like I did.&lt;/p&gt;
&lt;p&gt;At least, I wish I&amp;rsquo;d found something like this when I was starting out.
So today, I would like to describe my blogging setup in Emacs, tools I use outside of Emacs, and tweaks I made to make the process more automated.
Let&amp;rsquo;s begin!&lt;/p&gt;
&lt;h2 id=&#34;hugo&#34;&gt;Hugo&lt;/h2&gt;
&lt;p&gt;There are a lot of various static site generators (SSG) available today: Jekyll, Pelican, 11ty, e.t.c. - there are many of them.
At the time, I was looking for something that I could use with Emacs&amp;rsquo; Org Mode package because I really liked it, and a commonly suggested generator was &lt;a href=&#34;https://gohugo.io/&#34; target=&#34;_blank&#34;&gt;Hugo&lt;/a&gt;.
It has limited support for &lt;code&gt;.org&lt;/code&gt; file format, so I decided to try it.
Other than that, it is really fast, their template language is not hard and quite versatile, and there are a lot of themes to try.
I eventually made my own theme, so it is possible too.&lt;/p&gt;
&lt;p&gt;I must say, that I haven&amp;rsquo;t tried other SSGs, Hugo immediately worked for me, so I have no real opinion on why you should prefer Hugo to, say, Jekyll - it just works for me.
If you&amp;rsquo;re already using another static site generator, and it works for you, there&amp;rsquo;s no need to change it, unless you&amp;rsquo;re missing some features, possibly ones I will be going to talk about in this post.&lt;/p&gt;
&lt;p&gt;So without further ado, let&amp;rsquo;s set up a new blog with Hugo!&lt;/p&gt;
&lt;h3 id=&#34;hugo-setup&#34;&gt;Hugo setup&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m using Fedora Linux, so in my case installing Hugo is one command away:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo dnf install hugo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I don&amp;rsquo;t think there&amp;rsquo;s anything else you&amp;rsquo;ll need to start blogging, so the setup is really easy.
See the &lt;a href=&#34;https://gohugo.io/getting-started/installing/&#34; target=&#34;_blank&#34;&gt;getting started&lt;/a&gt; guide to see all other installation options.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;hugo&lt;/code&gt; command installed, we need a place, where we will store all blog-related files, let&amp;rsquo;s create a directory for it in the home directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir ~/blog ; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cd&lt;/span&gt; ~/blog
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order for Hugo to recognize this blog, it needs to have a certain file structure and a config file.
We&amp;rsquo;ll also need a theme for the blog, as Hugo doesn&amp;rsquo;t come with a pre-built one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git init .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can create a config file.&lt;/p&gt;
&lt;p&gt;A config file for Hugo uses the &lt;a href=&#34;https://toml.io/en/&#34; target=&#34;_blank&#34;&gt;TOML&lt;/a&gt; format, and is called &lt;code&gt;config.toml&lt;/code&gt;.
It has a quite simple structure, and there are standard things we need to take care in it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;baseurl = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;contentdir = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;publishdir = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;public&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;canonifyurls = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;relativeURLS = &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;theme = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ananke&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;My awesome blog&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;languageCode = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;en-us&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;summaryLength = 42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;copyright = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;copyright info, like license, year, author name, e.t.c.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[author]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Your Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[params]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;description = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Something about your blog&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;showFooterCredits = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;math = &lt;span style=&#34;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useIcon = &lt;span style=&#34;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[outputFormats]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[outputFormats.RSS]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mediatype = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;application/rss+xml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;baseName = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;feed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &lt;code&gt;~/blog/config.toml&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;I think this is a bare minimum you&amp;rsquo;ll need to start, but there are more options you can set here, or even create your own ones.
There&amp;rsquo;s a comprehensive &lt;a href=&#34;https://gohugo.io/getting-started/configuration/&#34; target=&#34;_blank&#34;&gt;configuration section&lt;/a&gt; on Hugo&amp;rsquo;s site that you can refer to for more details.
I&amp;rsquo;ve left out some bits, so we&amp;rsquo;ll return to the &lt;code&gt;config.toml&lt;/code&gt; file a bit later.&lt;/p&gt;
&lt;p&gt;Right now let&amp;rsquo;s focus on the top of the file - there are two variables that interesting for us &lt;code&gt;contentdir&lt;/code&gt; and &lt;code&gt;publishdir&lt;/code&gt;.
The &lt;code&gt;contentdir&lt;/code&gt; one is a place where &lt;code&gt;hugo&lt;/code&gt; will take markdown files from, and render them to static &lt;code&gt;html&lt;/code&gt; files put in the &lt;code&gt;bublishdir&lt;/code&gt;.
We will not use both of these directly, but you can try by putting the following markdown file into &lt;code&gt;posts&lt;/code&gt; directory inside the &lt;code&gt;contentdir&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title = &amp;#34;Hello there!&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;author = [&amp;#34;Your Name&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tags = [&amp;#34;some&amp;#34;, &amp;#34;tags&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;draft = false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;General Kenobi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  &lt;code&gt;~/blog/content/posts/hello.md&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;Now we can build our blog and serve it on &lt;code&gt;localhost&lt;/code&gt; with the &lt;code&gt;hugo server&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hugo server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Start building sites …
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hugo v0.93.3+extended linux/amd64 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;BuildDate&lt;/span&gt;=unknown
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   | EN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-------------------+-----
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Pages            | 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Paginator pages  |  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Non-page files   |  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Static files     |  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Processed images |  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Aliases          |  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Sitemaps         |  1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Cleaned          |  0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Built in 108 ms
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Watching &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; changes in /home/alist/blog/{content,themes}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Watching &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; config changes in /home/alist/blog/config.toml, /home/alist/blog/themes/ananke/config.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Environment: &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;development&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Serving pages from memory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Web Server is available at //localhost:1313/ (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;bind&lt;/span&gt; address 127.0.0.1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Press Ctrl+C to stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It should look something like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-16-my-blogging-setup-with-emacs-and-org-mode/first-steps.png&#34;
         alt=&#34;Figure 1: The blog homepage is on the left, and the post page is on the right&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;The blog homepage is on the left, and the post page is on the right&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Well, maybe not the most beautiful result, but this is just for demonstration purposes.
There are &lt;a href=&#34;https://themes.gohugo.io/&#34; target=&#34;_blank&#34;&gt;a lot of themes&lt;/a&gt; for Hugo, so you can choose any other you like.&lt;/p&gt;
&lt;p&gt;And this is pretty much it - you can start blogging right away, just create a markdown file as shown above, and Hugo will take care of the rest.
Except, I want to do it with Emacs and Org mode specifically, and if you do too, follow along.&lt;/p&gt;
&lt;h3 id=&#34;additional-hugo-things&#34;&gt;Additional Hugo things&lt;/h3&gt;
&lt;p&gt;There are many other things Hugo can do.
For example, you can create RSS feed for your blog, create alternative pages on your blog based on contents of your blog, e.t.c.&lt;/p&gt;
&lt;p&gt;Some settings are dependent on the theme.
So a lot of config options can be quite different from theme to theme, and it makes it a bit harder to try out other themes.
When I was writing about choosing a &lt;a href=&#34;https://andreyor.st/posts/2022-02-22-new-look/&#34;&gt;new look&lt;/a&gt; for my blog earlier this year, it was a major obstacle for me, so my advice would be to find a theme you like as early as possible, until your blog grows with a lot of custom settings, and other tweaks.
Well, it&amp;rsquo;s general advice - if you really will want to migrate to another theme you&amp;rsquo;ll do it no matter what, just know that it might be a bit problematic.&lt;/p&gt;
&lt;p&gt;Speaking of the theme-specific stuff, for example, my blog theme has a support for links section, which I set up like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links.link]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Gitlab&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;href = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://gitlab.com/andreyorst/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links.link]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Github&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;href = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://github.com/andreyorst/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links.link]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Tags&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;href = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/tags&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links.link]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Categories&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;href = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/categories&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links.link]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Archive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;href = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/posts&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.links.link]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;About&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;href = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/about&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will not work for &lt;code&gt;ananke&lt;/code&gt;, because it has its own notion of social-related links:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[params.ananke_socials]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;twitter&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;url = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;https://twitter.com/GoHugoIO&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So refer to the documentation of your theme of choice for this kind of stuff.&lt;/p&gt;
&lt;p&gt;Also, note that some links in my config are pointing to statically generated pages, like &lt;code&gt;/tags&lt;/code&gt; or &lt;code&gt;/categories&lt;/code&gt;.
Hugo automatically will generate these if the theme has a support for them, or if you&amp;rsquo;ve created your own templates.
For instance, the &lt;code&gt;ananke&lt;/code&gt; theme, we&amp;rsquo;re using for our example blog supports such, and if you will manually go to the &lt;code&gt;localhost:1313/tags&lt;/code&gt; you will see a list of tags, generated from the post we&amp;rsquo;ve created.
Even though we&amp;rsquo;ve never created this page ourselves.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;ve mentioned this is done with the template language.
For example, here&amp;rsquo;s how the &lt;code&gt;ananke&lt;/code&gt; theme handles creating this page:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;ul class=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;pa0&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {{ range .GetTerms &amp;#34;tags&amp;#34; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;lt;li class=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;list di&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;lt;a href=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{{ .RelPermalink }}&amp;#34;&lt;/span&gt; class=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;link f5 grow no-underline br-pill ba ph3 pv2 mb2 dib black sans-serif&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       {{- .LinkTitle -}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;lt;/a&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s a lot to dig in, so instead of explaining everything here and now, I&amp;rsquo;ll point you to the &lt;a href=&#34;https://gohugo.io/templates/introduction&#34; target=&#34;_blank&#34;&gt;documentation&lt;/a&gt; once again.
Yeah, I know, I&amp;rsquo;ve said it will be a comprehensive post, but I&amp;rsquo;m not going to write a full course on Hugo here.
It is an advanced stuff, and I didn&amp;rsquo;t know anything about that when I started, so you probably don&amp;rsquo;t need it too yet.
Just keep in mind that you can generate pages, and it is done by writing stuff in these &lt;code&gt;{{ }}&lt;/code&gt; expressions.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s get back on topic, and look at how we can do our blogging with the comfort of Emacs&lt;/p&gt;
&lt;h2 id=&#34;emacs&#34;&gt;Emacs&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re already an Emacs user, then great, you don&amp;rsquo;t need me to teach you how to install it, the packages, and so on.
If you&amp;rsquo;re not an Emacs user, then this section is probably not for you.
Two previous sections should be enough for a pretty decent blogging workflow with Markdown.&lt;/p&gt;
&lt;p&gt;But in my setup, I&amp;rsquo;m using &lt;a href=&#34;https://orgmode.org/&#34; target=&#34;_blank&#34;&gt;Org Mode&lt;/a&gt; instead of Markdown, for several reasons, which I won&amp;rsquo;t go into.
And the only text editor that supports Org in its full capacity is Emacs.
There are plugins for other text editors, like &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=vscode-org-mode.org-mode&#34; target=&#34;_blank&#34;&gt;this one for VSCode&lt;/a&gt;, but they&amp;rsquo;re not even close to what Org mode can offer.&lt;/p&gt;
&lt;p&gt;Org is not just a markup format, like many may think, it is actually an application within Emacs.
Editing &lt;code&gt;.org&lt;/code&gt; document is like working in something like an office suite - you have things to format text, but you also get stuff like spreadsheets, and you can run code to manipulate spreadsheets data.
Org comes with a variety of backends for exporting it to other formats, e.g. to LaTeX, HTML, ODT, or even plain Markdown.
We&amp;rsquo;re going to install such backend for exporting to &lt;a href=&#34;https://github.com/russross/blackfriday&#34; target=&#34;_blank&#34;&gt;Hugo-compatible markdown&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yes, Hugo uses a bit different Markdown, as there are a lot of so-called Markdown flavors, each with their own features, the most popular being GitHub-Flavored Markdown (or GFM for short).
For us, it&amp;rsquo;s not a problem, because we will be writing in Org, and the &lt;a href=&#34;https://github.com/kaushalmodi/ox-hugo&#34; target=&#34;_blank&#34;&gt;ox-hugo&lt;/a&gt; package will take care of the rest.&lt;/p&gt;
&lt;h3 id=&#34;ox-hugo&#34;&gt;&lt;code&gt;ox-hugo&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To install the &lt;code&gt;ox-hugo&lt;/code&gt; package, use whatever you&amp;rsquo;re using to install packages.
Again, refer to the &lt;a href=&#34;https://github.com/kaushalmodi/ox-hugo#installation&#34; target=&#34;_blank&#34;&gt;documentation&lt;/a&gt; if you&amp;rsquo;re not sure what to do.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;straight.el&lt;/code&gt; to install packages, and &lt;code&gt;use-package&lt;/code&gt; to manage configurations.
So in my case, the configuration for &lt;code&gt;ox-hugo&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox-hugo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:straight&lt;/span&gt; ( &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;github&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;kaushalmodi/ox-hugo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:branch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ox&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing special, yet.&lt;/p&gt;
&lt;p&gt;With this installed, we can start using &lt;code&gt;.org&lt;/code&gt; files in our blog instead of &lt;code&gt;.md&lt;/code&gt; files, but there are two ways of doing it.
First one is to use a single &lt;code&gt;.org&lt;/code&gt; file where all posts are stored together as headings.
Let&amp;rsquo;s call it post-per-subtree.
Second is to use separate &lt;code&gt;.org&lt;/code&gt; files for each post, or post-per-file.&lt;/p&gt;
&lt;p&gt;When I started this blog, I used the first approach, but as my blog grew bigger with more and more long posts with a lot of markup in them, images, LaTeX formulas, and other stuff, Emacs started struggling to edit this file.
It wasn&amp;rsquo;t that bad, but spell-checking gave me a lot of hard time, given that it sometimes wanted to process the whole file for some reason.
Still, unsatisfied with the results I&amp;rsquo;ve migrated my blog from post-per-subtree to post-per-file approach.
This is another example of what you should decide pretty early on - it is possible to migrate, but it is a considerable amount of manual work.
I had to move 61&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; posts from headings to files, set all frontmatter, and other stuff.&lt;/p&gt;
&lt;p&gt;I, personally, would suggest you to use post-per-file approach, but this is just my experience.
Ox-hugo&amp;rsquo;s docs actually suggest you to use post-per-subtree approach because it has some additional features, that you can&amp;rsquo;t get automatically when using post-per-file:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are 2 major blogging flows that can be used with this package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One post per Org subtree (preferred)
&lt;ul&gt;
&lt;li&gt;Export only the current post Org subtree, or&lt;/li&gt;
&lt;li&gt;Export all valid Hugo post subtrees in a loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;One post per Org file
&lt;ul&gt;
&lt;li&gt;This works but you won’t be able to leverage Org-specific benefits like tag and property inheritance, use of TODO states to translate to post draft state, auto weight calculation for pages, taxonomies and menu items, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See the Org Capture Setup page to see how to quickly create new posts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve used tagged headings and properties, and &lt;code&gt;TODO&lt;/code&gt; items as well, so once I&amp;rsquo;ve migrated these features were gone.
However, I don&amp;rsquo;t really miss these for a few reasons.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TODO&lt;/code&gt; items are handy, but really only for local workflow.
Hugo can skip building pages for posts that are marked with &lt;code&gt;draft&lt;/code&gt; property.
When setting the pipeline for building blog on something like GitHub/GitLab pages you usually want this.
When working locally, however, when you want to see how your text looks rendered, you can include &lt;code&gt;draft&lt;/code&gt; posts by specifying &lt;code&gt;-D&lt;/code&gt; argument to &lt;code&gt;hugo&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;I could use &lt;code&gt;draft&lt;/code&gt; by manually specifying it in the frontmatter, but in actuality, I just don&amp;rsquo;t commit exported &lt;code&gt;.md&lt;/code&gt; files for my draft posts.
So the lack of &lt;code&gt;TODO&lt;/code&gt; markers is not a problem in my workflow, as I usually work on a single post at a time.
It may be different for you.&lt;/p&gt;
&lt;p&gt;The lack of tags or properties is not a problem for me either.
A bit later I&amp;rsquo;ll show you my solution for tags, which I like even more than the old approach.
As for properties, I didn&amp;rsquo;t use them that much, so it may vary from user to user.&lt;/p&gt;
&lt;h3 id=&#34;writing-an-example-post-in-dot-org&#34;&gt;Writing an example post in &lt;code&gt;.org&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s try writing a post similarly to how we did with Markdown, but now with Org and &lt;code&gt;ox-hugo&lt;/code&gt;.
I will briefly touch both approaches for blogging flow, as described by &lt;code&gt;ox-hugo&lt;/code&gt;, but later on I will use post-per-file.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create a &lt;code&gt;blog.org&lt;/code&gt; file in the root directory or our blog:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-org&#34; data-lang=&#34;org&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+title&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: My awesome blog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+author&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: Your Name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_auto_set_lastmod&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_base_dir&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: .&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_section&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: .&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Posts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;:properties:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;:export_hugo_section: posts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;:end:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Hello There!                   :some:tags:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;:properties:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;:export_file_name: hello
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;:end:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;General Kenobi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Other post
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;:properties:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;:export_file_name: other-post
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;:end:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Keep bloggin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  &lt;code&gt;~/blog/blog.org&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;Now, with this file in place and &lt;code&gt;ox-hugo&lt;/code&gt; installed and loaded, you can put the cursor on one of the headings and press &lt;code&gt;C-c C-e&lt;/code&gt; shortcut (or call &lt;code&gt;org-export-dispatch&lt;/code&gt; function), and you should see a menu, something like this:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2022-10-16-my-blogging-setup-with-emacs-and-org-mode/export-dispatcher.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Press &lt;code&gt;H&lt;/code&gt;, followed by another &lt;code&gt;H&lt;/code&gt;, and &lt;code&gt;ox-hugo&lt;/code&gt; will generate an &lt;code&gt;.md&lt;/code&gt; file based on the &lt;code&gt;:properties:&lt;/code&gt; section under the heading.
Repeat for all headings, or press &lt;code&gt;H&lt;/code&gt; &lt;code&gt;A&lt;/code&gt; to export all headings.
The generated file will be almost identical to what we&amp;rsquo;ve written by hand before, with the only difference being that &lt;code&gt;ox-hugo&lt;/code&gt; will add the &lt;code&gt;lastmod&lt;/code&gt; property, indicating the last time this file was edited.
So if you&amp;rsquo;re exporting all subtrees beware that all &lt;code&gt;lastmod&lt;/code&gt; entries may be updated.&lt;/p&gt;
&lt;p&gt;To do the same thing with post-per-file approach, we&amp;rsquo;ll need a directory to store &lt;code&gt;.org&lt;/code&gt; files in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-org&#34; data-lang=&#34;org&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_base_dir&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: ../&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_section&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: posts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_auto_set_lastmod&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+title&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: Hello there!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#+hugo_tags&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;: some tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;General Kenobi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 4:&lt;/span&gt;
  &lt;code&gt;~/blog/post/hello.org&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;For this to work you need to specify the &lt;code&gt;hugo_base_dir&lt;/code&gt; to point to the root of the blog.
In case of file-per-subtree approach we had the &lt;code&gt;blog.org&lt;/code&gt; file in the root directory, so there the base directory was set to &lt;code&gt;./&lt;/code&gt;.
Since now, we&amp;rsquo;re inside the &lt;code&gt;~/blog/post/&lt;/code&gt; directory, the base directory is &lt;code&gt;../&lt;/code&gt;.
Just a small detail to be aware of.&lt;/p&gt;
&lt;p&gt;This mostly takes care on the general blogging workflow with &lt;code&gt;ox-hugo&lt;/code&gt;.
You either create a post per file in a dedicated directory, or use a single file for all posts.
Simple as that.&lt;/p&gt;
&lt;p&gt;The top section of the file, consisting of &lt;code&gt;#+&lt;/code&gt; things is a frontmatter, that is exported to the &lt;code&gt;.md&lt;/code&gt; file.
You can add custom elements to it, and specify other things like date, categories and so on.
I&amp;rsquo;m showing the bare minimum needed to get started, so you&amp;rsquo;ll need to explore other features by yourself.&lt;/p&gt;
&lt;h3 id=&#34;automating-things-with-emacs&#34;&gt;Automating things with Emacs&lt;/h3&gt;
&lt;p&gt;Once I migrated to post-per-file approach, I quickly realized how painful it is to write the frontmatter each time by hand.
So, following the advice from &lt;code&gt;ox-hugo&lt;/code&gt; I&amp;rsquo;ve created a sophisticated &lt;code&gt;org-capture&lt;/code&gt; template that takes care of a lot of things.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve created a so-called local feature, or inline package, if you will, for my Emacs configuration, with a lot of stuff related to my blogging workflow.
It&amp;rsquo;s a bit big, so I&amp;rsquo;ve hidden it, as I will go into details in a bit.
But you probably can just copy and paste this thing into your config, and it should work, if you have &lt;code&gt;use-package&lt;/code&gt;.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;A local blog package.&lt;/summary&gt;
&lt;div class=&#34;details&#34;&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-publish-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-generate-file-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-read-list-items&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-capture-template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#+hugo_base_dir: ../
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_section: posts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_auto_set_lastmod: t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+options: tex:dvisvgm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+macro: kbd @@html:&amp;lt;kbd&amp;gt;$1&amp;lt;/kbd&amp;gt;@@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+title: %(format \&amp;#34;%s\&amp;#34; blog--current-post-name)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+date: %(format-time-string \&amp;#34;%Y-%m-%d %h %H:%M\&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_tags: %(blog-read-list-items \&amp;#34;Select tags: \&amp;#34; &amp;#39;blog-tags)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_categories: %(blog-read-list-items \&amp;#34;Select categories: \&amp;#34; &amp;#39;blog-categories)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_custom_front_matter: :license %(format \&amp;#34;%S\&amp;#34; blog-license)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;%?&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Org-capture template for blog posts.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-tags&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A list of tags used for posts.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-categories&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A list of tags used for posts.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-directory&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/blog&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Location of the blog directory for org-capture.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-license&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Blog license string.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog--current-post-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Current post name for org-capture template.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-read-list-items&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Completing read items with the PROMPT from the VAR.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;VAR must be a quoted custom variable, which will be saved if new
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;items were read by the &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`completing-read&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-trim&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing-read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;customize-save-variable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sort&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&amp;lt;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-join&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-title-to-fname&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[[:space:]]&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-+&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[^[:alnum:]-]+&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;downcase&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-generate-file-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Title: &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog--current-post-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;find-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name-concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-directory&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;posts&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s-%s.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-title-to-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-publish-file&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Update &amp;#39;#+date:&amp;#39; tag, and rename the currently visited file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;File name is updated to include the same date and current title.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-match-data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;today&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;now&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%h %H:%M&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;re-search-forward&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^#\\+date:.*$&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#+date: %s %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;today&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;now&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;re-search-forward&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^#\\+title:[[:space:]]*\\(.*\\)$&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-title-to-fname&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-string&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rename-visited-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s-%s.org&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;today&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-match&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^[[:digit:]]\\{4\\}-[[:digit:]]\\{2\\}-[[:digit:]]\\{2\\}-\\(.*\\)$&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-string&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-already-exists&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;save-buffer&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;provide&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;This may look as a giant blob of weird looking code (because it is) so let&amp;rsquo;s dive into it.&lt;/p&gt;
&lt;p&gt;First things first, this is an &lt;code&gt;use-package&lt;/code&gt; directive for a non-existent feature &lt;code&gt;blog&lt;/code&gt;.
It may make some people question things, so the first thing you need to know is that the &lt;code&gt;:preface&lt;/code&gt; block runs before everything else, and at the end of it there is a &lt;code&gt;(provide &#39;blog)&lt;/code&gt; call.
So it works like a package, even though it is a part of the &lt;code&gt;init.el&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The first ting it does is creating a capture template:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-capture-template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#+hugo_base_dir: ../
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_section: posts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_auto_set_lastmod: t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+options: tex:dvisvgm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+macro: kbd @@html:&amp;lt;kbd&amp;gt;$1&amp;lt;/kbd&amp;gt;@@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+title: %(format \&amp;#34;%s\&amp;#34; blog--current-post-name)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+date: %(format-time-string \&amp;#34;%Y-%m-%d %h %H:%M\&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_tags: %(blog-read-list-items \&amp;#34;Select tags: \&amp;#34; &amp;#39;blog-tags)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_categories: %(blog-read-list-items \&amp;#34;Select categories: \&amp;#34; &amp;#39;blog-categories)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#+hugo_custom_front_matter: :license %(format \&amp;#34;%S\&amp;#34; blog-license)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;%?&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Org-capture template for blog posts.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This template is then bound to the capture dispatch menu.
As you can see it takes care of the frontmatter creation, as well as supplying some other info, such as date, post title, tags, e.t.c.&lt;/p&gt;
&lt;p&gt;Most of this stuff is taken from custom variables, defined afterwards:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-tags&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A list of tags used for posts.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-categories&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A list of tags used for posts.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-directory&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;~/blog&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Location of the blog directory for org-capture.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-license&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Blog license string.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;blog&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can use Custom to set these variables to values that are meaningful to your setup.&lt;/p&gt;
&lt;p&gt;Next, there&amp;rsquo;s a function for reading a list of tags or categories from the respecting lists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-read-list-items&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Completing read items with the PROMPT from the VAR.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;VAR must be a quoted custom variable, which will be saved if new
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;items were read by the &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`completing-read&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; function.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-trim&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing-read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-empty-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;remove&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;items&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;customize-save-variable&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sort&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;item&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;var&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&amp;lt;&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-join&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a bit sketchy, as it mutates the custom file, populating it with new tags, because I find it handy.
No need to remember all tags, when you can choose existing ones via a completion menu, and automatically remember new ones.
This function works for any custom variable that is a list of strings, so it may be handy for other purposes as well.&lt;/p&gt;
&lt;p&gt;Now, when I create posts, I want them to follow a certain format for a file names.
This format is &lt;code&gt;year-month-day-post-name.org&lt;/code&gt;.
The following functions take care of this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-title-to-fname&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread-last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[[:space:]]&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-+&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-regexp-in-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;[^[:alnum:]-]+&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;downcase&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-generate-file-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;read-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Title: &amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog--current-post-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;find-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name-concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-directory&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;posts&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s-%s.org&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-title-to-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;title&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first one is responsible for replacing all space characters with dashes, and removing consecutive dashes.
It also removes all non alpha-numeric characters from the name.
The second one is used during capturing.
It sets the &lt;code&gt;blog--current-post-name&lt;/code&gt; for the given title, creates a file, and names it accordingly to the format I&amp;rsquo;ve mentioned.&lt;/p&gt;
&lt;p&gt;This mostly takes care about capturing, but there are often situations when I&amp;rsquo;ve updated the date of the post (because I was working on it for several days, and capture stored the initial one), or when I updated a title, and I want file-name to reflect that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-publish-file&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Update &amp;#39;#+date:&amp;#39; tag, and rename the currently visited file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;File name is updated to include the same date and current title.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-match-data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;today&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;now&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%h %H:%M&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;re-search-forward&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^#\\+date:.*$&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;replace-match&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;#+date: %s %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;today&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;now&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;re-search-forward&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^#\\+title:[[:space:]]*\\(.*\\)$&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-title-to-fname&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-string&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;condition-case&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rename-visited-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s-%s.org&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;today&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string-match&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;^[[:digit:]]\\{4\\}-[[:digit:]]\\{2\\}-[[:digit:]]\\{2\\}-\\(.*\\)$&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;match-string&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-already-exists&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;save-buffer&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function does a basic replace of the date with the current date, and renames the visited file accordingly.
So it is meant to be used only when editing a file that is a post in the blog.&lt;/p&gt;
&lt;p&gt;With this set of functions, and a capture template I don&amp;rsquo;t need anything more for a comfortable blogging experience.
And compared to post-per-subtree flow, I don&amp;rsquo;t need to write any &lt;code&gt;:properties:&lt;/code&gt; blocks, with export file name that uses my date-based format, which I previously did manually, but now I just call &lt;code&gt;blog-publish-file&lt;/code&gt; once I&amp;rsquo;ve decided that the post is ready.&lt;/p&gt;
&lt;p&gt;Last but not least, the settings for &lt;code&gt;org-capture&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org-capture&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:defer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org-directory&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-directory&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;org-capture-templates&lt;/span&gt; `((&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Post&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-generate-file-name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            ,&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;blog-capture-template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:jump-to-captured&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:immediate-finish&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This capture template is the only one I&amp;rsquo;m using right now, and it essentially only needed to fill all the parts of the template, and then jump to the captured file.&lt;/p&gt;
&lt;h3 id=&#34;spell-checking&#34;&gt;Spell-checking&lt;/h3&gt;
&lt;p&gt;Another thing worth mentioning is checking text for spelling mistakes.
I actually use two tools in Emacs: the inbuilt &lt;code&gt;flyspell&lt;/code&gt; package, and the &lt;a href=&#34;https://github.com/mhayashi1120/Emacs-langtool&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;langtool.el&lt;/code&gt;&lt;/a&gt; package, which is a client for the &lt;a href=&#34;https://languagetool.org/&#34; target=&#34;_blank&#34;&gt;language tool&lt;/a&gt; server.&lt;/p&gt;
&lt;p&gt;Flyspell is enough to check most spelling mistakes in regular words, though it often doesn&amp;rsquo;t know a lot of tech-related stuff.
It doesn&amp;rsquo;t require any setup, except the installation of the dictionary, which is then detected automatically.&lt;/p&gt;
&lt;p&gt;LanguageTool is more about writing style, catching the wrong usage of times, and other such mistakes.
It mostly works without any setup, though, I had to fix a small bug in its implementation.
Here&amp;rsquo;s my config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-check-buffer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-check-buffer@fix-narrowing&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-installation-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-installation-dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:preface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-installation-dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Path to the local installation of langtool.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;choice&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:tag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;not installed&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:tag&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Langtool installation directory&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;langtool&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defvar&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-args&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ngrams&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;ngrams-en-20150817&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-installation-dir&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-exists-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ngrams&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;--languageModel &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ngrams&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-language-tool-jar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;languagetool-commandline.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-installation-dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-java-user-arguments&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-language-tool-server-jar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;languagetool-server.jar&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-installation-dir&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-http-server-host&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-server-user-arguments&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-args&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;langtool-check-buffer&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fix-narrowing&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;save-mark-and-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;use-region-p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;push-mark&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;push-mark&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-max&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lang&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the best results, I highly recommend &lt;a href=&#34;https://languagetool.org/download/ngram-data/&#34; target=&#34;_blank&#34;&gt;downloading&lt;/a&gt; the &lt;code&gt;ngram&lt;/code&gt; data archive (8 GB), uncompressing it to the installation directory, and passing it as an argument for &lt;code&gt;langtool&lt;/code&gt;.
That way, it will find more mistakes.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve considered using &lt;a href=&#34;https://www.grammarly.com/&#34; target=&#34;_blank&#34;&gt;Grammarly&lt;/a&gt;, and as far as I know, it has better detection, based on an AI model, but it also requires registration, and it is a paid service, while &lt;code&gt;langtool&lt;/code&gt; can be used locally, and it is an open source solution.
You can always try both and pick the one you liked more.
Or just use both of them, though they sometimes think differently.&lt;/p&gt;
&lt;h2 id=&#34;my-workflow&#34;&gt;My workflow&lt;/h2&gt;
&lt;p&gt;So, the workflow in my blog looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x org-capture RET&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt; - fire up capture menu, and select the post entry with the &lt;code&gt;p&lt;/code&gt; key;&lt;/li&gt;
&lt;li&gt;Enter posts title;&lt;/li&gt;
&lt;li&gt;Fill in tags and categories;&lt;/li&gt;
&lt;li&gt;Edit;&lt;/li&gt;
&lt;li&gt;Re-publish, if I&amp;rsquo;ve changed the title, or the date has changed;&lt;/li&gt;
&lt;li&gt;Export to Hugo Markdown;&lt;/li&gt;
&lt;li&gt;Commit and push, wait for the deploy to finish.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a recording of me doing this:&lt;/p&gt;
&lt;p&gt;&lt;video controls muted class=&#34;invertable&#34;&gt;&lt;source src=&#34;https://andreyor.st/2022-10-16-my-blogging-setup-with-emacs-and-org-mode/whole-process.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I like how tag reading interface prevents me from accidentally adding the same tags by removing already added ones from the list.
And I can always correct mistakes, like a wrong title, and don&amp;rsquo;t do any manual file renaming.
Overall this process is pleasant, I must say, and I like it more than with the post-per-subtree approach.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s the last part, the deployment of the blog to, in my case, GitLab pages.
I&amp;rsquo;m using a rather simple &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file, that simply builds the site for me every time I push:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image: registry.gitlab.com/pages/hugo/hugo_extended:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pages:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  script:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - hugo --minify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  artifacts:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    paths:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - public
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  only:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simple as that.&lt;/p&gt;
&lt;p&gt;I went with GitLab because I wanted a private repository - I don&amp;rsquo;t think there&amp;rsquo;s a need for other people to see my drafts, and I don&amp;rsquo;t really want to keep the git history clean, to be honest.
The blog repo is like a pile of thoughts I throw into it, and then selectively publish ones that I think worth it.&lt;/p&gt;
&lt;p&gt;So, if you&amp;rsquo;ve followed this post&amp;rsquo;s examples, the whole &lt;code&gt;~/blog&lt;/code&gt; directory by now should look something like that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tree -a ~/blog
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── blog.org          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# if you want to go post-per-subtree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── posts             &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# if you want to go post-per-file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── hello.org
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── config.toml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── content
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── posts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│       └── hello.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── .git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── .gitlab-ci.yml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── .gitmodules
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── themes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── ananke
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;hugo server&lt;/code&gt; in this directory should give you a preview of the blog, and you can experiment with templates, themes, and other stuff without actually deploying it.
Also, when editing &lt;code&gt;.org&lt;/code&gt; files, and re-exporting them via &lt;code&gt;ox-hugo&lt;/code&gt;, Hugo will detect changes and live reload the active page if needed.
It&amp;rsquo;s really handy, and you can actually use it as a live preview by putting a browser side by side to Emacs, or by using something like &lt;code&gt;eww&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;should-you-start-blogging&#34;&gt;Should you start blogging?&lt;/h2&gt;
&lt;p&gt;Yes, I believe so.&lt;/p&gt;
&lt;p&gt;Even if your blog will not be as big as some of your favorite blogs, you&amp;rsquo;ll notice a lot of benefits after some amount of time.
As I mentioned at the beginning of this post, I started capturing a lot more thoughts after I started writing things in 2020.
There were a lot of various thoughts running through my head before 2020, but I never gave them time to get a shape.
Now if I feel like something might be interesting, I grab my laptop and start writing.
Even if I will later discard the idea, and trash all text I&amp;rsquo;ve written, it&amp;rsquo;s still a win, because I understood that the idea wasn&amp;rsquo;t really good, or that I can&amp;rsquo;t write about it just yet.&lt;/p&gt;
&lt;p&gt;So in my opinion, blogging can improve your ability to give thoughts shape and form.
There&amp;rsquo;s a famous quote by Leslie Lamport:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you’re thinking without writing, you only think you’re thinking&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think it&amp;rsquo;s true.
Quite often I can think about a problem hard enough, and feel like I&amp;rsquo;m not able to come to some solution.
Then I open a chat with my coworker and start writing a long message that I&amp;rsquo;m going to send them, with a thorough problem description, and things I&amp;rsquo;ve already tried.
By the middle of such a message, usually, I already know the answer to my question or I&amp;rsquo;m figuring out a solution, so I just don&amp;rsquo;t send the message.
You can think about it as the &amp;ldquo;Rubber Duck Debugging&amp;rdquo; method, but without a duck, and instead of talking to a toy I&amp;rsquo;m writing a draft message to a coworker.&lt;/p&gt;
&lt;p&gt;So yeah, if you ever had a thought that you maybe should have a blog, then absolutely go for it.
And I hope that this post can be helpful to make the process easier.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;many of them are &amp;ldquo;hidden&amp;rdquo;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: My blogging setup with Emacs and Org Mode&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 16 Oct 2022 16:57:00 +0300</pubDate>
    </item><item>
      <title>GNOME doesn&#39;t need to be that huge</title>
      <link>https://andreyor.st/posts/2022-10-07-gnome-doesnt-need-to-be-that-huge/</link>
      <guid>https://andreyor.st/posts/2022-10-07-gnome-doesnt-need-to-be-that-huge/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been a GNOME Shell user for many years now - I&amp;rsquo;ve started using it pretty much since its initial release in 2011.
I&amp;rsquo;m using GNU/Linux as my main operating system since 2008, and I started with Ubuntu, as many did back then, and what I liked about Ubuntu was its desktop environment, or DE for short.
Back then Ubuntu was using Gnome 2, a predecessor to GNOME Shell (or Gnome 3), and it was great - very well thought out, customizable, responsible, and lightweight.
However, with the release of Ubuntu 10.10, Canonical moved to their own DE, called &lt;a href=&#34;https://en.wikipedia.org/wiki/Unity_%28user_interface%29&#34; target=&#34;_blank&#34;&gt;Unity&lt;/a&gt;, and I found myself in a weird situation.&lt;/p&gt;
&lt;p&gt;The Gnome project just announced GNOME Shell, but Ubuntu moved to its own solution.
And both options were, well, how do I put it… buggy?&lt;/p&gt;
&lt;p&gt;In my opinion, Unity wasn&amp;rsquo;t good up until the release of Ubuntu 12.04, and it became really good in 14.04.
Well, at least that&amp;rsquo;s how I remember it.
I didn&amp;rsquo;t like Unity so I continued to use Gnome 2 for several years.&lt;/p&gt;
&lt;p&gt;GNOME Shell, on the other hand…
Let&amp;rsquo;s just say that it became really good just recently with the release of GNOME 40.
Up until the release of GNOME 3.28 it wasn&amp;rsquo;t really that good, there were performance issues, occasional crashes, and other problems.
Combined with the tendency of breaking extensions with every release, and the overall direction Gnome developers took, it wasn&amp;rsquo;t the best option, again, in my opinion, especially when Unity was making good progress.
But, Canonical decided that Unity isn&amp;rsquo;t that great, Unity8 wasn&amp;rsquo;t making good progress, and with the release of Ubuntu 17.10, they&amp;rsquo;ve moved to GNOME Shell too.
However, they&amp;rsquo;ve used gnome 3.26 and it wasn&amp;rsquo;t particularly great at the time, as I&amp;rsquo;ve mentioned it.&lt;/p&gt;
&lt;p&gt;Now, you may wonder - why I&amp;rsquo;m only talking about Ubuntu?
There were, of course, other distributions that used Gnome at the time, it&amp;rsquo;s just I used Ubuntu back then so that&amp;rsquo;s what I remember personally.
I&amp;rsquo;m no longer an Ubuntu user though, I&amp;rsquo;ve moved to Fedora, simply because it has a vanilla Gnome, without any stupid things put on top of it by the developers of the distribution, like extra extensions or themes.
Yes, I prefer Gnome as is - default Adwaita theme, no extensions that change the UI, like docks.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s still one problem that I think is somewhat serious, and it is a common problem with a lot of interfaces today.
And I noticed this problem when Ubuntu changed to Gnome in the 17.10 release.
You see, Unity was made to be something &lt;em&gt;in between&lt;/em&gt; - something more modern than Gnome 2, yet not &lt;em&gt;as modern&lt;/em&gt; as Gnome 3.
When Gnome 3 was released in 2011 it was looking rather different from Gnome 2.
Unity, on the other hand, kept the good things of Gnome 2, yet expanded on some usability features, like good support for the global menu and HUD.
The in-app menu search in Unity was amazing, but I&amp;rsquo;m going away from the topic.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s common between most modern interfaces as of today?
They&amp;rsquo;re all &lt;em&gt;big&lt;/em&gt;.
And so was Gnome, already in the year 2011 going way ahead of its time.&lt;/p&gt;
&lt;h2 id=&#34;mobile-oriented-ui&#34;&gt;Mobile-oriented UI&lt;/h2&gt;
&lt;p&gt;With the increased popularity of mobile devices, there also was the rise of mobile-oriented designs.
Web pages now have a dedicated mobile-friendly mode, where all elements are bigger, so it is more comfortable to navigate with a bare finger, which provides far lower precision than a mouse pointer.
Mobile apps use similar designs to web pages, even to the extent that some mobile apps are made with web technologies, and some web pages can be installed as an app.&lt;/p&gt;
&lt;p&gt;A tablet is another quite popular device type, quite similar to a smartphone but bigger and more aimed at surfing the web.
However, even though it usually has a bigger screen, it is still used with fingers as the main input device, so the UI elements are still big so users could reliably navigate them.&lt;/p&gt;
&lt;p&gt;Desktops, however, don&amp;rsquo;t suffer from this, as they have a touchpad/trackpoint/trackball/mouse to control the pointer with great precision, and rarely have a touch screen, though the latter became more popular lately.
But the popularity of mobile devices impacted the desktop UI guidelines as well.
The first victims were desktop versions of the mobile-first web pages - they were either just stretched-up mobile versions or desktop variants that were stylized after their mobile versions.
And it started to creep into the desktop UI itself.
And Gnome and macOS are affected by it the most.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a Mac user, you know that visually macOS gets closer and closer to the iPad OS with each release.
Perhaps that&amp;rsquo;s because they want to unify the operating systems, and make the iPad a fully featured portable computer at some point, similar to Microsoft Surface.
Maybe, it&amp;rsquo;s just my guess - I&amp;rsquo;m not an Apple user and won&amp;rsquo;t likely be one.
But what this means is that UI elements are getting bigger and more spaced out, in order to be usable on both desktop and portable devices with touch screens.
There&amp;rsquo;s a &lt;a href=&#34;https://www.andrewdenty.com/blog/2020/07/01/a-visual-comparison-of-macos-catalina-and-big-sur.html&#34; target=&#34;_blank&#34;&gt;great post by Andrew Denty&lt;/a&gt;, which has a lot of images, comparing Catalina and Big Sur versions of macOS.
Here&amp;rsquo;s one of the images from that post:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/4-notification-preferences-macos-catalina-big-sur-comparison.png&#34;
         alt=&#34;Figure 1: macOS Catalina on the left, Big Sur on the right&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;macOS Catalina on the left, Big Sur on the right&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If you look at the window &lt;em&gt;headerbar&lt;/em&gt;, you&amp;rsquo;ll notice that it is almost twice as big, as it was before.
Well, not twice, but about ~1.4x bigger - the old one is 76px tall, and the new one is 106px:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/notifications-stacked.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Yet the close, minimize and maximize buttons size remains the same.
Other elements also have bigger padding, making the UI more &lt;em&gt;spacy&lt;/em&gt;.
I guess it is considered beautiful, but I also think that this is a waste of screen space.
Macs are unlikely to get touch screens any time soon, and even if they are, the increased height of the headerbar won&amp;rsquo;t make a difference for the user, who&amp;rsquo;s trying to touch the minimize button right next to the close button.
So I don&amp;rsquo;t think it was a change needed to make macOS closer to having the touch-ready interface, but a pure stylistic one.&lt;/p&gt;
&lt;p&gt;But, well, the post title was about Gnome, and here we are, talking about macOS - why?
Well, because Gnome takes a lot of inspiration from macOS, as far as I can see, at least.
See for yourself:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/finder-and-nautilus.png&#34;
         alt=&#34;Figure 2: macOS Finder and Gnome File Manager&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;macOS Finder and Gnome File Manager&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Yeah, yeah, I know, a Mac user will say that it&amp;rsquo;s not even close, but the inspiration is pretty clear to me.
Nikitonsky even used Gnome&amp;rsquo;s settings app screenshot as a joke after a &lt;a href=&#34;https://twitter.com/nikitonsky/status/1557357661171204098&#34; target=&#34;_blank&#34;&gt;long thread&lt;/a&gt; on the redesign of the settings window in the macOS Ventura beta version:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/nikitonsky-tweet.png&#34;
         alt=&#34;Figure 3: @nikitonsky tweet&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;&lt;a href=&#34;https://twitter.com/nikitonsky/status/1559538442412900352&#34; target=&#34;_blank&#34;&gt;@nikitonsky tweet&lt;/a&gt;&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Well, enough with the comparison to macOS, let&amp;rsquo;s get back to the main topic.&lt;/p&gt;
&lt;h2 id=&#34;mobile-oriented-desktop-ui-dot-dot&#34;&gt;Mobile-oriented &lt;em&gt;desktop&lt;/em&gt; UI?..&lt;/h2&gt;
&lt;p&gt;Yeah, you&amp;rsquo;ve read that right - Gnome wants to be on mobile phones and on the desktop at the same time.
Their UI is designed with this idea in mind.
A lot of apps change layout when you resize the window to be more like a screen of the phone:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted style=&#34;border-radius: 16px&#34;&gt;&lt;source src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/gnome-responsive-ui.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This is a nice &lt;em&gt;touch&lt;/em&gt; indeed, and I can appreciate the effort, especially since there are ways to run Gnome on mobile phones today.
Alternatives are always good and given the sad state of Android as an operating system, I&amp;rsquo;m all for full-blown Linux on mobile devices, with nice-looking native apps.
And while this is cool and all, here&amp;rsquo;s a big problem:&lt;/p&gt;
&lt;p&gt;Gnome interface elements are just way too big on the desktop.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a screenshot of the Gnome desktop on a Full HD display:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/15%27%27full-hd.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;And here&amp;rsquo;s a similar screenshot but on a 2K display:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/13%27%272k.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Just by visual comparison, you can see how much more space the file manager window is using on the first screenshot.
Note, however, that both screenshots have file manager windows of the very same size, e.g. there&amp;rsquo;s no interface scaling.
If you have a 1920×1080 display, try opening both screenshots in full screen, to see how the UI scale &lt;em&gt;changes&lt;/em&gt; with the resolution.
I, unfortunately, don&amp;rsquo;t have two displays with the same diagonal size but different resolutions, but here&amp;rsquo;s how it looks on my two laptops, from which I&amp;rsquo;ve taken the screenshots.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: After getting a few &lt;a href=&#34;https://www.reddit.com/r/gnome/comments/xy0uov/comment/iretitl/?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&#34; target=&#34;_blank&#34;&gt;comments&lt;/a&gt; on the fact that comparison screenshots don&amp;rsquo;t show anything useful, as the file manager windows have the same pixel size, I understood that I was not quite exact on what I wanted people to see.
The problem in my explanation was with the fact that while windows do have the same size, the text size was supposed to be different but I forgot to enable it.
Sorry for the confusion, and thanks for pointing this out.
I&amp;rsquo;ve enabled font scaling and re-made the screenshots, so I hope that now this will illustrate my point a bit better.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a screenshot of a display with a resolution of 1920×1200:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/regular1920x1200.png&#34;
         alt=&#34;Figure 4: UI scale: 100%, display resolution: 1920×1200, font scale: 1x&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;UI scale: 100%, display resolution: 1920×1200, font scale: 1x&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is how I see things on my work laptop, which has no UI or font scaling&lt;/p&gt;
&lt;p&gt;Now the same image, but I&amp;rsquo;ve downscaled 2560×1600 to 1920×1200 and upscaled fonts to 1.33x.
This way the images will have the same size, but you&amp;rsquo;ll see the difference in the UI element sizes:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/2k-downscalded-to-1920x1200-with-upscaled-fonts.png&#34;
         alt=&#34;Figure 5: UI scale: 75%, display resolution: 2560×1600, font scale: 1.33x&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 5: &lt;/span&gt;UI scale: 75%, display resolution: 2560×1600, font scale: 1.33x&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You can toggle between these screenshots to see the difference in UI scale.
I, naturally, see it on screen, given that I use the latter setup on my smaller laptop, and the first screenshot represents the setup on my work laptop.
And I indeed had to adjust the size of the file manager window so their geometry matched, however, note that the text size is the same&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; on both screenshots:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/text-size-same.png&#34;
         alt=&#34;Figure 6: UI elements are scaled down, yet the text is the same size&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 6: &lt;/span&gt;UI elements are scaled down, yet the text is the same size&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I understand that this was not very obvious to see from the screenshots I provided earlier, that&amp;rsquo;s why I&amp;rsquo;ve included laptop photos that should have demonstrated this idea.
Hopefully, these screenshots better illustrate my point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first one has a 15-inch Full HD display, the second one has a 13-inch 2K display:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/screen-sizes.jpg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now, let&amp;rsquo;s set the screen scale on the 13-inch laptop to 125% and compare:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/screen-sizes-scaled.jpg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;It may seem that apps don&amp;rsquo;t have the same size, but that&amp;rsquo;s due to the fact that the screens have different heights, and actually, 125% scaling matches how the screen would look if I had a 2k 15-inch display, instead of a 13-inch one.
Here&amp;rsquo;s a better illustration:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/screen-sizes-scaled-adjusted.jpg&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve used my GIMP skills to increase the height of the second display to match the height of the first display.
You can see that the file manager windows are indeed (almost) the same size.
Well, I guess I could just add a screenshot with the system scale set to 125% but the post already has way too many images, so if you want to compare them, see the footnotes section &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;, &lt;/sup&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;, &lt;/sup&gt;&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;So what do I want you to take away from all of this?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using the laptop on the left for 9 hours a day because it&amp;rsquo;s my work laptop.
And each day I do I feel that the interface could have been 25% smaller.
Notably, I felt this way even before I got myself a laptop with a higher resolution - and when I did I realized that Gnome works perfectly with this kind of pixel density.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using the right laptop right before and after work.
This is basically my hobby machine - I write this blog on it, and I code all my side projects on this very screen.
And every time I use Gnome apps on this screen they feel right at home.
I don&amp;rsquo;t have the best eyesight, mind you, so small elements should be problematic for me, but with this level of scale, they simply are not small - they&amp;rsquo;re &lt;strong&gt;normal&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So my takeaway here is that Gnome can safely &lt;strong&gt;reduce all their UI element sizes by 25%&lt;/strong&gt; and it will still work great!
Like, seriously, I even used &lt;code&gt;~/.config/monitors.xml&lt;/code&gt; to set the UI scale to &lt;code&gt;0.75&lt;/code&gt; under the Wayland session, which looks amazing&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; on my 1920×1080 display UI-wise.
The text is a bit too small for my liking, but this can be fixed by scaling fonts up, the main thing I wanted from this is to make UI elements take less space.
All UI elements such as buttons, menus, headerbars, panels, e.t.c. are perfectly usable with this scale on a regular Full HD display.
The same can be done under XOrg with &lt;code&gt;xrandr --output &amp;lt;display&amp;gt; --scale1.25x1.25&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On a side note, I once owned a &lt;a href=&#34;https://www.gpd.hk/gpdpocket/&#34; target=&#34;_blank&#34;&gt;GPD Pocket&lt;/a&gt;, the first revision, and it had a 7-inch screen with a 1920×1200 resolution.
I&amp;rsquo;ve used Gnome on it, and funnily enough, upon installation Gnome detected that the screen is small, and automatically set the interface scale to 200%.
Fractional scaling is still an experimental option, so I guess it was rounded to the next non-fractional scale available.
Using it like this was not possible at all, because nothing was able to fit on the screen.
I don&amp;rsquo;t have the device anymore, but I can set the scale to 200% on my work laptop and add it via GIMP to an old photo I&amp;rsquo;ve taken in 2018:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/gpd-with-gnome.png&#34;
         alt=&#34;Figure 7: A mockup of how Gnome looked on GPD Pocket with scaling set to 200%&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 7: &lt;/span&gt;A mockup of how Gnome looked on GPD Pocket with scaling set to 200%&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Setting the scaling to back 100% made the device usable but the text was too small.
So I&amp;rsquo;ve turned font scaling only, and could use Gnome on this tiny screen without any hiccups -  because all UI elements were perfectly usable in their unscaled form.
GPD Pocket also has a touch screen, and even the it wasn&amp;rsquo;t affected by scale change - all elements still could have been pressed reliably with ease.
I hope you can now trust me that the Gnome UI elements can be smaller without impacting usability because I&amp;rsquo;ve used Gnome on a large variety of screen sizes and resolutions.&lt;/p&gt;
&lt;h2 id=&#34;big-for-the-sake-of-being-big--or-just-different&#34;&gt;Big for the sake of being big (or just different?)&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s another thing I&amp;rsquo;d like to mention.
Gnome is quite different from other desktop environments available for GNU/Linux.
There are a lot of different DEs, of course, but the most common ones to pop up are KDE Plasma, XFCE4, MATE, and Cinnamon.
All these DEs are not &amp;ldquo;big&amp;rdquo; in terms of their UI elements.
KDE is more Windows-like, and Xfce and Mate are more Gnome2-like (well, Mate &lt;strong&gt;is&lt;/strong&gt; a continuation of Gnome2).
While Xfce and Mate are more of an old-school type of DEs, which are still mostly using UI guidelines from that era of Gnome2 but build on top of modern GTK, KDE is not.
KDE aims at being modern UI, without being big, and somehow that&amp;rsquo;s possible too!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve used KDE Plasma 5 for two whole years from 2017 to 2019 if I remember correctly.
Even though I always was a Gnome user before that, I enjoyed my time with KDE, after I got past the initial setup.
KDE, ships with a ton of settings, unlike Gnome, and for some reason, the KDE dev team decided to turn most of them on.
It was a major barrier for me because I want my desktop to be as simple as possible, not as noisy as possible.
So I had to turn off all these jumping cursor animations, loading circles, e.t.c. speed up window animations one step up, and so on.
After that KDE felt like a big improvement over what I&amp;rsquo;ve had in other Gnome2-like desktops.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/plasma.png&#34;
         alt=&#34;Figure 8: Official KDE Plasma 5.25 screenshot&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 8: &lt;/span&gt;Official KDE Plasma 5.25 screenshot&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;While I liked KDE, I&amp;rsquo;m just more familiar with Gnome, so I&amp;rsquo;ve returned to it after some time, but KDE was what made me start thinking about smaller interface elements again.
I also wanted Wayland, and KDE didn&amp;rsquo;t have great support for it back then, while Gnome kinda did.&lt;/p&gt;
&lt;p&gt;But what&amp;rsquo;s interesting, is that KDE Plasma also &lt;a href=&#34;https://plasma-mobile.org/&#34; target=&#34;_blank&#34;&gt;can be used on mobile phones&lt;/a&gt;, yet they don&amp;rsquo;t use mobile UI on desktop, unlike Gnome.
I&amp;rsquo;m not sure if Plasma mobile ships with completely different apps or reuses apps from the desktop, but as far as I can tell, all apps that are built with the &lt;a href=&#34;https://develop.kde.org/frameworks/kirigami/&#34; target=&#34;_blank&#34;&gt;Kirigami framework&lt;/a&gt; can work as both desktop and mobile apps, similarly to Gnome.
So it can be done, even without using a big UI on a desktop.
Gnome just didn&amp;rsquo;t want to do that, unfortunately.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll admit, there are &lt;a href=&#34;https://www.deepin.org/en/dde/&#34; target=&#34;_blank&#34;&gt;other desktop environments&lt;/a&gt; with big UI elements, it&amp;rsquo;s just the fact that Gnome is one of the most used desktop environments in the Linux ecosystem.
Gnome is used by default by two major out-of-the-box distributions - Fedora and Ubuntu.
It is used by default in Pop_OS!, Tails, Debian, CentOS, and RHEL, and even Oracle&amp;rsquo;s Solaris &lt;a href=&#34;https://en.wikipedia.org/wiki/Oracle_Solaris#Version_history&#34; target=&#34;_blank&#34;&gt;switched to it in version 11.4&lt;/a&gt;.
This is why I think that there should be put a bit more thought on the UI guidelines, as all these distributions are not for the mobile market.&lt;/p&gt;
&lt;h2 id=&#34;it-s-getting-better&#34;&gt;It&amp;rsquo;s getting better&lt;/h2&gt;
&lt;p&gt;Though I don&amp;rsquo;t like decisions that were made in the past by the Gnome developers, I must admit - Gnome is getting better with every release.
Gnome 40 introduced a lot of tweaks to the UI, making workspaces horizontal by default for example, and changing the overview screen to better utilize space because of it.
The dark mode is another new addition, and it is made good, though it&amp;rsquo;s not automatic, you need to use an extension for that, but it&amp;rsquo;s &lt;em&gt;fine&lt;/em&gt;.
What I&amp;rsquo;m saying is that the project is lively and ever-changing - maybe we&amp;rsquo;ll get a more desktop-oriented design in the future.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve mentioned that I prefer not to use extensions, but in actuality, I use two extensions - &lt;a href=&#34;https://github.com/kaiseracm/gnome-shell-extension-maximize-to-empty-workspace&#34; target=&#34;_blank&#34;&gt;maximize-to-empty-workspace&lt;/a&gt; and &lt;a href=&#34;https://nightthemeswitcher.romainvigier.fr/&#34; target=&#34;_blank&#34;&gt;Night Theme Switcher&lt;/a&gt;.
Because of the first one, I&amp;rsquo;ve adopted the workflow, that I think the Gnome team envisioned - one maximized window per workspace.
Thus the big UI elements are not that of a problem, for me, at least, given that most of the screen is used by the maximized app, and I usually don&amp;rsquo;t stack multiple windows on one workspace.&lt;/p&gt;
&lt;p&gt;Even though, I think Gnome shouldn&amp;rsquo;t use these huge UI elements, or at least should provide a variant of the default theme that has 20-25% smaller window-related elements.
If this were done, I could use fractional scaling on my 2k laptop display, making text slightly bigger, while still having more usable space on my other Full HD laptop.
But we&amp;rsquo;ll see, I guess.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and let&amp;rsquo;s hope that Gnome will become even better in the future!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;There is a small rounding error after upscaling fonts to 1.333333, so the text sizes are not exactly same, but very close.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Gnome file manager at &lt;a href=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/15%27%27full-hd.png&#34;&gt;1920×1080 with a scale of 100%&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Gnome file manager at &lt;a href=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/13%27%272k.png&#34;&gt;2560×1600 with a scale of 100%&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Gnome file manager at &lt;a href=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/13%27%272k-scaled.png&#34;&gt;2560×1600 with a scale of 125%&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;Gnome file manager at &lt;a href=&#34;https://andreyor.st/2022-10-07-gnome-doesnt-need-to-be-that-huge/15%27%27full-hd-downscaled.png&#34;&gt;1920×1080 with a scale of 75%&lt;/a&gt; (resolution was artificially increased by scale settings in &lt;code&gt;~/.config/monitors.xml&lt;/code&gt;)&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: GNOME doesn&#39;t need to be that huge&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 07 Oct 2022 02:45:00 +0300</pubDate>
    </item><item>
      <title>Reproducible Research with Org Mode, Fennel, and LÖVE</title>
      <link>https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/</link>
      <guid>https://andreyor.st/posts/2022-09-26-reproducible-research-with-org-mode-fennel-and-love/</guid>
      <description>&lt;p&gt;Today I would like to talk about three separate tools, and how we can combine them with the power of Emacs.&lt;/p&gt;
&lt;p&gt;Our tools for today are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://fennel-lang.org&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; - a Lisp-like surface syntax for Lua that makes programming in Lua fun and more robust.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://orgmode.org/&#34; target=&#34;_blank&#34;&gt;Org Mode&lt;/a&gt; - a markup language and an application inside Emacs, which allows its users to create documents that include interactive pieces of code.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt; - a game engine that allows programming games in Lua.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This post is itself a program, describing how you could create similar Org documents and explore &lt;a href=&#34;https://en.wikipedia.org/wiki/Literate_programming&#34; target=&#34;_blank&#34;&gt;literate programming&lt;/a&gt;/&lt;a href=&#34;https://en.wikipedia.org/wiki/Reproducibility#Reproducible_research&#34; target=&#34;_blank&#34;&gt;reproducible research&lt;/a&gt; with Fennel, or other languages for that matter.
It&amp;rsquo;s possible thanks to Org Mode and my new package &lt;a href=&#34;https://gitlab.com/andreyorst/ob-fennel&#34; target=&#34;_blank&#34;&gt;ob-fennel&lt;/a&gt;, which implements necessary functions for sending Fennel code blocks to the REPL process.
For a better experience, you should read this in Emacs, and you can get the original &lt;code&gt;.org&lt;/code&gt; file from &lt;a href=&#34;https://andreyor.st/2022-09-26-reproducible-research-with-org-mode-fennel-and-love.org&#34;&gt;here&lt;/a&gt;.
If you want to follow the instructions, make sure to &lt;a href=&#34;https://fennel-lang.org/setup&#34; target=&#34;_blank&#34;&gt;install Fennel&lt;/a&gt; and &lt;a href=&#34;https://github.com/love2d/love/releases&#34; target=&#34;_blank&#34;&gt;LÖVE&lt;/a&gt; for this to work.&lt;/p&gt;
&lt;h2 id=&#34;bootstrapping-löve&#34;&gt;Bootstrapping LÖVE&lt;/h2&gt;
&lt;p&gt;First, we need to bootstrap LÖVE so it could understand Fennel code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; fennel = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;fennel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.insert(package.loaders &lt;span style=&#34;font-weight:bold&#34;&gt;or&lt;/span&gt; package.searchers, fennel.searcher)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve required &lt;code&gt;fennel&lt;/code&gt; the library and registered the &lt;code&gt;fennel.searcher&lt;/code&gt; function as one of the functions responsible to loading files.
With that, theoretically, we no longer need to write any more Lua code, and instead, we can write in Fennel, and then use plain Lua&amp;rsquo;s &lt;code&gt;require&lt;/code&gt; to load the files.
Let&amp;rsquo;s create a REPL (Read Eval Print Loop) that will allow us to do interactive programming in LÖVE via its thread and event systems.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s require &lt;code&gt;fennel&lt;/code&gt; once again, and also require &lt;code&gt;love.event&lt;/code&gt;.
Next, we&amp;rsquo;ll do a little trick that I&amp;rsquo;ll explain later, but for now, we&amp;rsquo;ll only need to capture the module-scope value of &lt;code&gt;...&lt;/code&gt; into variables &lt;code&gt;event&lt;/code&gt; and &lt;code&gt;channel&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fennel&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;require &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:love.event&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will make sense in a moment.
Now, we need a REPL itself.
REPL consists of the prompt that asks for more input, and the loop that calls the prompt which reads some input and sends it to a channel.
Let&amp;rsquo;s define the &lt;code&gt;prompt&lt;/code&gt; function first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-line?&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;io.write &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-line?&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.. &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;gt;&amp;gt; &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.flush&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io.read&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can create the infinite loop, that will read from &lt;code&gt;stdin&lt;/code&gt; and push the read value into LÖVE&amp;rsquo;s event system.
That&amp;rsquo;s where we&amp;rsquo;ll use the captured &lt;code&gt;event&lt;/code&gt; variable, however, we&amp;rsquo;ll need to run this loop only in a LÖVE thread, so we&amp;rsquo;ll check if the &lt;code&gt;channel&lt;/code&gt; was bound:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;while &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:demand&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;table.concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.event.push&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cont?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;print &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string.format&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%s error: %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;accumulate &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;msg&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;tostring &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;message&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once data appears in the channel, this function exterminates what pattern it received.
It is always a table, where the first element means the kind of data, and the rest of the table is the data itself.
That&amp;rsquo;s the protocol we&amp;rsquo;re going to write in a moment.&lt;/p&gt;
&lt;p&gt;The loop check if the &lt;code&gt;event-type&lt;/code&gt; is either &lt;code&gt;:data&lt;/code&gt; or &lt;code&gt;:error&lt;/code&gt; and acts accordingly.
In addition to that, there&amp;rsquo;s a third event-type &lt;code&gt;:next-line&lt;/code&gt; which represents the situation when the REPL receives incomplete input and waits for more lines.
Let&amp;rsquo;s implement this protocol:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl.fnl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.compileString&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.newFileData&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:repl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newThread&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.thread.newChannel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coro&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.create &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fennel.repl&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$...&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;-&amp;gt;&amp;gt; &lt;/span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:readChunk&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:read&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;stack-size&lt;/span&gt; 0)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coroutine.yield&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onValues&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:onError&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:push&lt;/span&gt; [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:error&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;...&lt;/span&gt;]))}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.resume &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coro&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;thread&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:start&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:eval&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;io-channel&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.handlers.eval&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;coroutine.resume &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coro&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is an asynchronous REPL, made with Lua&amp;rsquo;s coroutines.
You may wonder, how it will start the &lt;code&gt;loop&lt;/code&gt; function if it was under the &lt;code&gt;when channel&lt;/code&gt; guard, but that&amp;rsquo;s exactly what this piece of code does.&lt;/p&gt;
&lt;p&gt;First, it loads itself via &lt;code&gt;love.filesystem.read&lt;/code&gt; and compiles Fennel code to Lua via &lt;code&gt;fennel.compileString&lt;/code&gt; function.
Next, this compiled representation is used to create a &lt;a href=&#34;https://love2d.org/wiki/FileData&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;FileData&lt;/code&gt;&lt;/a&gt; object, that is used to start a LÖVE thread with the &lt;code&gt;love.thread.newThread&lt;/code&gt; function.
So this module will be executed twice - first when &lt;code&gt;main.lua&lt;/code&gt; loads the file, and second, when LÖVE spawns the thread, but were not there, yet.&lt;/p&gt;
&lt;p&gt;After we&amp;rsquo;ve created the &lt;code&gt;thread&lt;/code&gt; we create an &lt;code&gt;io-channel&lt;/code&gt; and the REPL coroutine.
Next, we start the &lt;code&gt;coroutine&lt;/code&gt; by passing it a table of functions, each of which will &lt;code&gt;push&lt;/code&gt; data to the &lt;code&gt;io-channel&lt;/code&gt;.
Importantly, the &lt;code&gt;readChunk&lt;/code&gt; function pauses the coroutine after every read, allowing it to run asynchronously within the main thread.&lt;/p&gt;
&lt;p&gt;Finally, we start the &lt;code&gt;thread&lt;/code&gt; by passing &lt;code&gt;:eval&lt;/code&gt; which will be bound to the &lt;code&gt;event&lt;/code&gt; variable, and &lt;code&gt;io-channel&lt;/code&gt; which will be bound to &lt;code&gt;channel&lt;/code&gt;.
This thread spins the &lt;code&gt;loop&lt;/code&gt; function, which blocks the thread waiting for the input, while the main LÖVE thread continues to run.&lt;/p&gt;
&lt;p&gt;With all of that, we can finally &lt;code&gt;require&lt;/code&gt; the &lt;code&gt;repl.fnl&lt;/code&gt; file in the &lt;code&gt;main.lua&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;repl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, let&amp;rsquo;s disable vsync while we&amp;rsquo;re at it.
For some reason, it makes the REPL slow on my machine.
We won&amp;rsquo;t be needing it anyway:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love&lt;/span&gt;.&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conf&lt;/span&gt;(t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  t.window.vsync = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can start hacking in real time!&lt;/p&gt;
&lt;h2 id=&#34;drawing-plots&#34;&gt;Drawing plots&lt;/h2&gt;
&lt;p&gt;Since we&amp;rsquo;re done with the literate programming example, let&amp;rsquo;s look at how the reproducible research can be organized.
I&amp;rsquo;m sure you should be familiar with the concept of a notebook, like &lt;a href=&#34;https://rmarkdown.rstudio.com/&#34; target=&#34;_blank&#34;&gt;R Markdonw&lt;/a&gt; or &lt;a href=&#34;https://jupyter.org/&#34; target=&#34;_blank&#34;&gt;Jupiter&lt;/a&gt;.
We&amp;rsquo;re going to achieve something like that.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re reading this file in Emacs, which you should, press the &lt;code&gt;C-c C-v t&lt;/code&gt; shortcut, which will run the &lt;code&gt;org-babel-tangle&lt;/code&gt; function.
After executing it, Emacs will create three files &lt;code&gt;main.lua&lt;/code&gt;, &lt;code&gt;conf.lua&lt;/code&gt;, and &lt;code&gt;repl.fnl&lt;/code&gt; in the same directory as this file.
If you&amp;rsquo;re not reading this file in Emacs, then, well, get Emacs, or just believe me - it works.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s plot a function via LÖVE2D and Fennel.
I&amp;rsquo;m not sure if there&amp;rsquo;s a library for drawing plots with LÖVE, but it&amp;rsquo;s ain&amp;rsquo;t fun to use something like that anyways, so let&amp;rsquo;s build our own!
First, we&amp;rsquo;ll need a &lt;a href=&#34;https://love2d.org/wiki/Canvas&#34; target=&#34;_blank&#34;&gt;Canvas&lt;/a&gt; object to draw to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.newCanvas&lt;/span&gt; 640 480))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Put the cursor in this source code block and press &lt;code&gt;C-c C-c&lt;/code&gt; shortcut (or call the &lt;code&gt;org-babel-execute-src-block&lt;/code&gt; function with &lt;code&gt;M-x&lt;/code&gt;)
The empty LÖVE window will appear, and Emacs will display a message in the prompt area, with the contents something like &amp;ldquo;Please re-evaluate once Fennel is initialized&amp;rdquo;.
We won&amp;rsquo;t be needing this window, so you can minimize it - we&amp;rsquo;ll be drawing off-screen onto a canvas and then saving it as an image.
Org-mode provides us with all we&amp;rsquo;ll need to preview results without leaving Emacs.&lt;/p&gt;
&lt;p&gt;Once Fennel is loaded, and all threads were spawned, hit &lt;code&gt;C-c C-c&lt;/code&gt; again, and you should see &lt;code&gt;&amp;quot;nil&amp;quot;&lt;/code&gt; in the echo area.
This means that the code was executed successfully and the &lt;code&gt;canvas&lt;/code&gt; variable was created.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s write a function that will draw a grid to the active canvas.
First, we&amp;rsquo;ll need a function that will calculate the grid step based on the zoom level.
Our zoom level is represented in percentages, which we&amp;rsquo;ll later convert to values by dividing by &lt;code&gt;100&lt;/code&gt;.
However, for our grid, we will be doing an infinite zoom with finite details.&lt;/p&gt;
&lt;p&gt;This function computes the step between each grid line based on current &lt;code&gt;zoom&lt;/code&gt; level.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calc-step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gscale&lt;/span&gt; (^ 10 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bit.bor&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.log &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 10) 0))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 100 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gscale&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit convoluted, but the key here is the bitwise &lt;code&gt;or&lt;/code&gt; operator - that&amp;rsquo;s what makes our grid cycle between zoom levels properly.
We now can define the function that computes and draws the grid itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-grid&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calc-step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [1 1 1 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.rectangle&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fill&lt;/span&gt; 0 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;[[(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 10) [0.7 0.7 0.7 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 1000) 1000)]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    [(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 1) [0.9 0.9 0.9 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;% &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 1000) 1000))]]])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt; []]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:into&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;] [0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;color&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;grid&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function actually draws two grids - one for unit size, and one for 1/10 of the unit size, and applies dynamic transparency based of the &lt;code&gt;zoom&lt;/code&gt; level.
This way, we can create an illusion of the infinite zoom level, that
It&amp;rsquo;s a bit verbose, but all it really does is create a table of line segments from the center of the canvas in all four directions with the calculated &lt;code&gt;step&lt;/code&gt; interval.&lt;/p&gt;
&lt;p&gt;This only draws the grid, though, we also need to draw the X and Y axis, with some markings indicating the zoom level:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axis&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;calc-step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [0.3 0.3 0.3 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [0 (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 5)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;))) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 5) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%.1f&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;))) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 5) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.print&lt;/span&gt; 0 (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 5) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;5 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function works similarly to the &lt;code&gt;draw-grid&lt;/code&gt; one, except it only draws two lines intersecting at the canvas&amp;rsquo; center, and the numbers, indicating units of measure.
Each number also has a small mark at the axis for better readability.&lt;/p&gt;
&lt;p&gt;Finally, let&amp;rsquo;s write a function &lt;code&gt;plot&lt;/code&gt; that will accept a function &lt;code&gt;fun&lt;/code&gt; which it will plot on the canvas, and some additional arguments, like &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;to&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;.
Also, did I mention that you should press &lt;code&gt;C-c C-c&lt;/code&gt; &lt;strong&gt;on each code block&lt;/strong&gt; in this section?
It will send the code to the running LÖVE process, and we will be able to see the results dynamically.
But before we do that, let&amp;rsquo;s write a function that transforms so-called world coordinates to screen coordinates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [(&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; 2)) (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)) (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt; 2))]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oh, and we also need a function for generating a unique file name for the output image:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ext&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.match &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;(.*)%.(.-)$&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.getInfo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ext&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt; 0) 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;base&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;suffix&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ext&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alright, here&amp;rsquo;s the &lt;code&gt;plot&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; [{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;result.png&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:renderTo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     #(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 100) 100)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-grid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [1 0 0 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;points&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;to&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; 0.1)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;points&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;points&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:newImageData&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:encode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:png&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.getSaveDirectory&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function uses the &lt;a href=&#34;https://love2d.org/wiki/Canvas:renderTo&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;renderTo&lt;/code&gt;&lt;/a&gt; method of the &lt;code&gt;canvas&lt;/code&gt; object.
It accepts an anonymous function, which draws the gird, the axis, sets the color of the plot to red, and finally draws the plot with &lt;code&gt;love.graphics.points&lt;/code&gt;.
We can execute it like that, by pressing &lt;code&gt;C-c C-c&lt;/code&gt; on the next code block:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from&lt;/span&gt; -50 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:to&lt;/span&gt; 50 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:step&lt;/span&gt; 0.01 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 5000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;This produces an image, which you should see if you call the &lt;code&gt;org-toggle-inline-images&lt;/code&gt; function.
As you can see, it plots a simple &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_3731252ebff9619616923189ae68cffd87243765.svg&#34; alt=&#34;\(x^2\)&#34; class=&#34;org-svg&#34; /&gt; function, but we can plot any other, like &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_6d8bccd3ef0e0eaa85bfa9ec415d47791e2b8900.svg&#34; alt=&#34;\(\tan(\sin(x))\)&#34; class=&#34;org-svg&#34; /&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.tan &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.sin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from&lt;/span&gt; -10 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:to&lt;/span&gt; 10 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 5000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result1.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Or a more complex example would be generating a square wave via this formula &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_6d8ca5aa31feffe0dccb81a596a0322bc3db7924.svg&#34; alt=&#34;\(\sum_{k=1,3,5,7,...,29}^{} \frac{sin(x\mul{k})}{k}\)&#34; class=&#34;org-svg&#34; /&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:fun&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold&#34;&gt;accumulate &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.sin &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fcollect&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; 3 29 2] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;math.sin &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:from&lt;/span&gt; -500 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:to&lt;/span&gt; 500 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:step&lt;/span&gt; 0.01 &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 8000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result2.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You get the idea.&lt;/p&gt;
&lt;p&gt;Additionally, we can create a function that plots Org tables, like this one:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;table--lines&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;x&lt;/th&gt;
&lt;th&gt;y&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;-7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The function is mostly similar to &lt;code&gt;plot&lt;/code&gt; except instead of calling a function it just goes through each table row, and builds line segments to draw:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot-table&lt;/span&gt; [{&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unique-fname&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;result.png&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:renderTo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     #(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;/ &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;or &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt; 1000) 100)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;h&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.getCanvas&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:getDimensions&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-grid&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw-axis&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setColor&lt;/span&gt; [1 0 0 1])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.setLineWidth&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;each &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ipairs &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;match &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;. &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world-&amp;gt;screen-coordinates&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;next-row&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;zoom&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.graphics.line&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y2&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:newImageData&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:encode&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:png&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;string.format &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;.. &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;love.filesystem.getSaveDirectory&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can plot it like this, passing the table via the &lt;code&gt;:var data=lines&lt;/code&gt; header property:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;plot-table&lt;/span&gt; {&lt;span style=&#34;font-weight:bold&#34;&gt;: &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:zoom&lt;/span&gt; 1000})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/ox-hugo/result3.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;You can build more complex functions, that, for example, draw several graphs on the same canvas, or draw entirely different types of graphs altogether.
Though this requires defining functions for all these kinds of visualizations, and I guess this is why people tend to use other languages for the task, like R.&lt;/p&gt;
&lt;h2 id=&#34;inline-evaluation&#34;&gt;Inline evaluation&lt;/h2&gt;
&lt;p&gt;Well, graphs are cool and all, but what about supplying values into the text directly?
We can do that too, and although, we could do this in our LÖVE REPL, that&amp;rsquo;s a great opportunity to showcase another ability of Org Babel - run multiple instances of Fennel, using completely different environments!&lt;/p&gt;
&lt;p&gt;For example, suppose we have some kind of a formula, that, for example, calculates the &lt;a href=&#34;https://en.wikipedia.org/wiki/Ackermann_function&#34; target=&#34;_blank&#34;&gt;Ackermann function&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 0) 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; 0) (&lt;span style=&#34;font-weight:bold&#34;&gt;* &lt;/span&gt;2 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1) 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; 1)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can define the function &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_08e585494f53002724747488de2bb88e8c747eb3.svg&#34; alt=&#34;\(n^2\)&#34; class=&#34;org-svg&#34; /&gt; using the &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(fn square [n] (A 1 n))&lt;/code&gt;&lt;/span&gt;, and use it like &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(square 4)&lt;/code&gt;&lt;/span&gt; producing &lt;code&gt;16&lt;/code&gt; as a result.
Or, we can define a function that computes &lt;img src=&#34;https://andreyor.st/ltximg/2022-09-26-reproducible-research-with-org-mode-fennel-and-love_4b35030e5268b8d41819f83682871bc4a74d81f7.svg&#34; alt=&#34;\(2\uparrow\uparrow{n}\)&#34; class=&#34;org-svg&#34; /&gt; like this: &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(fn two⇈n [n] (A 2 n))&lt;/code&gt;&lt;/span&gt;.
Calling it as &lt;span class=&#34;inline-src language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;code&gt;(two⇈n 4)&lt;/code&gt;&lt;/span&gt; gives us &lt;code&gt;65536&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These code blocks are running in a separate session, using a regular Lua interpreter, instead of our LÖVE REPL.
This is done by specifying the &lt;code&gt;:session&lt;/code&gt; header argument, and giving it a name, which instructs &lt;code&gt;ob-fennel&lt;/code&gt; to spawn a new process.
Upon exporting, the results of the inline evaluation would update automatically which eliminates the problem of stale data in the paper.
The results always reflect the actual code they were computed with.&lt;/p&gt;
&lt;h2 id=&#34;the-power-of-org&#34;&gt;The power of Org&lt;/h2&gt;
&lt;p&gt;The examples above are just the tip of the iceberg of what you can do with the Org package.
Back when I wasn&amp;rsquo;t an Emacs user, I often found threads on the topic &amp;ldquo;why should I use Emacs?&amp;rdquo; and each of these threads contained at least one answer which just said &amp;ldquo;Org Mode&amp;rdquo;.
I never understood why - what&amp;rsquo;s so good about Org that I can&amp;rsquo;t get from, say, Markdown?&lt;/p&gt;
&lt;p&gt;Since then, I&amp;rsquo;ve switched to Emacs and started this blog, using Org Mode, Hugo, and the &lt;a href=&#34;https://ox-hugo.scripter.co/&#34; target=&#34;_blank&#34;&gt;ox-hugo&lt;/a&gt; package.
Org mode has a built-in exporting engine, which can export &lt;code&gt;.org&lt;/code&gt; files to PDF, ODT, LaTeX, Markdown, or HTML files.
The ox-hugo package adds another backend for this engine, which exports to Hugo compatible markdown, which is then used by Hugo to build this website.&lt;/p&gt;
&lt;p&gt;And when I was starting this blog, I wasn&amp;rsquo;t sure that I made the right investment - I&amp;rsquo;ve just switched to Emacs a couple of months before, and I&amp;rsquo;m using this Org thing for writing.
I was uneasy because if I would stop enjoying writing in this setup I might lose all motivation for writing altogether.
But thankfully, I&amp;rsquo;ve liked the Org+Hugo combination, and it became the reason why I haven&amp;rsquo;t left Emacs since - it&amp;rsquo;s just too good as a writing experience.&lt;/p&gt;
&lt;p&gt;Literate programming was the way I learned Org.
I&amp;rsquo;ve &lt;a href=&#34;https://github.com/andreyorst/dotfiles/blob/21ef6737690678a5e29d47e0563df095e25cd873/.config/emacs/README.org&#34; target=&#34;_blank&#34;&gt;used it to configure Emacs&lt;/a&gt; because Org Mode provides a way to load &lt;code&gt;.org&lt;/code&gt; files as Emacs Lisp files, and you can replace your &lt;code&gt;init.el&lt;/code&gt; with &lt;code&gt;init.org&lt;/code&gt; if you want to.
But to be honest, it&amp;rsquo;s a fun experiment, but I don&amp;rsquo;t find literate programming to be that practical.
It&amp;rsquo;s even harder to consider, given that there aren&amp;rsquo;t a lot of tools besides Emacs, that allows writing programs in this style using &lt;em&gt;any&lt;/em&gt; language.
And you can&amp;rsquo;t just make your coworkers use Emacs all of a sudden.
Yes, there are solutions specific to a particular language, but they lack usability in my opinion.&lt;/p&gt;
&lt;p&gt;Reproducible research was a hot topic lately, and the growing popularity of Jupiter notebooks is a great indication.
Org Mode might not provide all the fancy UI elements, that Jupiter notebook has, but theoretically speaking, nothing prevents you from writing a UI in a standalone tool, like the game engine, and using it as a rendering frontend from the comfort of Emacs.
This post partly shows this, although, I went a more static route with embedded images.
But still, anything is possible if you have the dedication to do it.&lt;/p&gt;
&lt;p&gt;I hope this post was an interesting read, and you&amp;rsquo;ve become interested in Emacs and Org Mode, or even in Fennel and LÖVE combo.
Feel free to contact me if you have any questions on the topic.
See you soon!&lt;/p&gt;&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Reproducible Research with Org Mode, Fennel, and LÖVE&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 26 Sep 2022 00:57:00 +0300</pubDate>
    </item><item>
      <title>Function that can be called a limited amount of times</title>
      <link>https://andreyor.st/posts/2022-09-17-function-that-can-be-called-a-limited-amount-of-times/</link>
      <guid>https://andreyor.st/posts/2022-09-17-function-that-can-be-called-a-limited-amount-of-times/</guid>
      <description>&lt;p&gt;Recently I&amp;rsquo;ve stumped upon a &lt;a href=&#34;https://www.reddit.com/r/rust/comments/xelzrv/function_that_can_only_be_called_a_set_number_of/&#34; target=&#34;_blank&#34;&gt;Reddit thread&lt;/a&gt; about defining a function that you can call a limited amount of times in Rust, with compile-time check, and I wondered if I can make the same thing in Clojure.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;def-n-times-fn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fnspec&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  `(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x#&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; ~&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; A compile-time counter.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f#&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;~&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;~@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fnspec&lt;/span&gt;)] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; The function object, that will be called at runtime.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;~&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;name &lt;/span&gt;[&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args#&lt;/span&gt;]   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; Generation of a new macro with the name of the function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; that will manage the counter.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pos? &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;deref &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x#&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; And if the counter isn&amp;#39;t greater than zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt;                    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; an exception is thrown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-info&lt;/span&gt; ~(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t use `%s` more than %s times!&amp;#34;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;str &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;name&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;) {})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dec&lt;/span&gt;)      &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; otherwise, we decrement the counter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;list* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f#&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args#&lt;/span&gt;)))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; and generate a call&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, this is a macro-generating macro!
I&amp;rsquo;ll go into details in a bit, but let&amp;rsquo;s just appreciate the power of macros here.
Not only we can run all kinds of code at compile time, but we can also use all features that we often rely on at runtime, like lexical scope and closures!
And even though I wouldn&amp;rsquo;t really use a such macro in real code, I find the ability to do such things fascinating.&lt;/p&gt;
&lt;p&gt;We can use the macro like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;def-n-times-fn&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It acts similarly to &lt;code&gt;defn&lt;/code&gt; macro in Clojure, except instead of a function it generates a macro, named &lt;code&gt;vaiv&lt;/code&gt; in this case, that will be later expanded to an actual function call.
For example, we can wrap calls to it in a function, ensuring that the actual calls are delayed, and only compilation of these calls occurs.
I&amp;rsquo;ve put all of this into a file &lt;code&gt;foo.clj&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---snip---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (defmacro defn-n-times-fn ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; (def-n-times-fn 4 ...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ---8&amp;lt;---snap---8&amp;lt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; 1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; 2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; 3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; 4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; 5))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if we try to compile it, we&amp;rsquo;ll get an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ clojure -M -e &amp;#34;(compile &amp;#39;foo)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Syntax error macroexpanding vaiv at (foo.clj:25:3).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;can&amp;#39;t use `vaiv` more than 4 times!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nice!
And if we comment out one of the calls to &lt;code&gt;vaiv&lt;/code&gt; the compilation is successful:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ clojure -M -e &amp;#34;(compile &amp;#39;foo)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;foo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So what exactly happens here?
If we &lt;code&gt;macroexpand&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; the call to &lt;code&gt;defn-n-times-fn&lt;/code&gt; we&amp;rsquo;ll see that it just generates a new &lt;code&gt;vaiv&lt;/code&gt; macro and a function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x__5686__auto__&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;atom&lt;/span&gt; 4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f__5687__auto__&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defmacro &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; [&amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args__5688__auto__&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pos? &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x__5686__auto__&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ex-info&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;can&amp;#39;t use `vaiv` more than 4 times!&amp;#34;&lt;/span&gt; {})))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;swap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x__5686__auto__&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dec&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;list* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f__5687__auto__&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;args__5688__auto__&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So far nothing related to compile time usage checking happened just yet.
This changes whenever later uses of &lt;code&gt;vaiv&lt;/code&gt; itself expand to calls:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;macroexpand &lt;/span&gt;&amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; 42))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo/eval5694/vaiv--5695&lt;/span&gt;] 42)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s no check in the generated code either, because the check happened during the expansion of the macro, and is invisible to the user.
Every expansion of the &lt;code&gt;vaiv&lt;/code&gt; macro decrements the counter, and once we&amp;rsquo;ve expanded the code enough times it will fire an error.&lt;/p&gt;
&lt;p&gt;Pretty simple!
(If you can look past the meta-meta-programming, that is.)&lt;/p&gt;
&lt;p&gt;Though, this comes with limitations, such that this function can&amp;rsquo;t be passed into other functions, like &lt;code&gt;map&lt;/code&gt; or &lt;code&gt;filter&lt;/code&gt;.
Both because this is not actually a function, but a macro that expands to function call, and because it&amp;rsquo;s impossible to know at compile time how many times &lt;code&gt;map&lt;/code&gt; will invoke this function.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a way to outsmart the check by using any kind of loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 5]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works, because from the macro-expansion standpoint there&amp;rsquo;s only one invocation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.walk/macroexpand-all&lt;/span&gt; &amp;#39;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dotimes &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 5] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vaiv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n__6088__auto__&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;long &lt;/span&gt;5)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;loop*&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n__6088__auto__&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;foo/eval13775/vaiv--13776&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (vaiv i)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;unchecked-inc&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;i&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nevertheless, this was an interesting exercise in writing macros.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I&amp;rsquo;ve slightly edited the output of &lt;code&gt;macroexpand&lt;/code&gt;, mainly removing a lot of &lt;code&gt;clojure.core/&lt;/code&gt; prefixes for a more concise code.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Function that can be called a limited amount of times&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 17 Sep 2022 22:39:00 +0300</pubDate>
    </item><item>
      <title>Understanding transducers</title>
      <link>https://andreyor.st/posts/2022-08-13-understanding-transducers/</link>
      <guid>https://andreyor.st/posts/2022-08-13-understanding-transducers/</guid>
      <description>&lt;p&gt;Some time ago I ported most of Clojure&amp;rsquo;s &lt;code&gt;core&lt;/code&gt; namespace to Fennel and made it into a library called &lt;a href=&#34;https://github.com/andreyorst/fennel-cljlib&#34; target=&#34;_blank&#34;&gt;fennel-cljlib&lt;/a&gt;.
This was my first library for Fennel, so it wasn&amp;rsquo;t really great in terms of how it was implemented.
While it was making Fennel more like Clojure syntax-wise, which I like, it wasn&amp;rsquo;t following Clojure&amp;rsquo;s semantics that well.
The main thing that was missing is a proper &lt;code&gt;seq&lt;/code&gt; abstraction, which Clojure relies on for providing both lazy sequences and generic functions that can work on any data type that implements &lt;code&gt;ISeq&lt;/code&gt;.
Such functions are &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;take&lt;/code&gt; and so on.&lt;/p&gt;
&lt;p&gt;Since then, I&amp;rsquo;ve made a &lt;a href=&#34;https://github.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;few&lt;/a&gt; &lt;a href=&#34;https://github.com/andreyorst/fennel-async&#34; target=&#34;_blank&#34;&gt;more&lt;/a&gt; &lt;a href=&#34;https://github.com/andreyorst/fennel-conditions&#34; target=&#34;_blank&#34;&gt;libraries&lt;/a&gt; for Fennel, which were somewhat more narrowly focused, and one of such libraries was &lt;a href=&#34;https://github.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy-seq&lt;/a&gt; - an implementation of Clojure&amp;rsquo;s lazy sequences.
It doesn&amp;rsquo;t feature chunked sequences, (yet, &lt;em&gt;maybe&lt;/em&gt;), but it implements almost all sequence-related functions from Clojure.
And you can throw pretty much any Lua data structure that implements &lt;code&gt;pairs&lt;/code&gt; or &lt;code&gt;ipairs&lt;/code&gt; into it, and it will work out how to lazily transform it into a sequence.&lt;/p&gt;
&lt;p&gt;This was one of the missing pieces for the fennel-cljlib, as its implementation of &lt;code&gt;seq&lt;/code&gt; simply made a shallow copy of a given object in a linear time, making sure that the result is sequential.
With the implementation of &lt;code&gt;seq&lt;/code&gt; from the lazy-seq library, I could rewrite fennel-cljlib, also making all sequence-related functions lazy.
And while this will make the library more Clojure-like one piece is still missing from both fennel-cljlib and lazy-seq libraries.&lt;/p&gt;
&lt;p&gt;Transducers.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m quite familiar with transducers, well, I &lt;em&gt;use&lt;/em&gt; them regularly at work, and I read about their implementation a few years ago.
However, I&amp;rsquo;ve never implemented a transduceable context, i.e. a function that accepts a transducer, and applies it to elements of a given collection.
So, as a part of &lt;a href=&#34;https://gitlab.com/andreyorst/fennel-cljlib/-/merge_requests/15&#34; target=&#34;_blank&#34;&gt;the rewrite&lt;/a&gt; of the fennel-cljlib library, I needed not only to port transducers themselves, but I also had to implement such functions as &lt;code&gt;into&lt;/code&gt;, &lt;code&gt;transduce&lt;/code&gt;, and &lt;code&gt;sequence&lt;/code&gt;, which are transduceable contexts.&lt;/p&gt;
&lt;p&gt;Thankfully, &lt;code&gt;into&lt;/code&gt; and &lt;code&gt;transduce&lt;/code&gt; are written in Clojure, and are very straightforward to understand, but the &lt;a href=&#34;https://github.com/clojure/clojure/blob/5ffe3833508495ca7c635d47ad7a1c8b820eab76/src/clj/clojure/core.clj#L2664-L2687&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;sequence&lt;/code&gt;&lt;/a&gt; function is not.
Here&amp;rsquo;s its source code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;) ())))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang.RT/chunkIteratorSeq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang.TransformerIterator/create&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang.RT/iter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;colls&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang.RT/chunkIteratorSeq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang.TransformerIterator/createMulti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.lang.RT/iter&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;colls&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ())))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is written mostly via Java interop, and I can&amp;rsquo;t use this in my port of the &lt;code&gt;clojure.core&lt;/code&gt; namespace to Fennel, because Fennel runs on Lua, and Lua can&amp;rsquo;t really interop with Java.
So I had to reimplement this function in Fennel, and this is what motivated me to write this post.
Also, I don&amp;rsquo;t really know Java, so understanding how &lt;code&gt;sequence&lt;/code&gt; works was a challenge on its own&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The interesting thing is, after I&amp;rsquo;ve tried to implement this function several times, I understood that I, actually, don&amp;rsquo;t understand transducers as well as I thought.
So I had to go back a bit and learn how transducers actually work, and why are they written the way they are.
It was really fascinating, and after a bit of trial and error, I managed to implement &lt;code&gt;sequence&lt;/code&gt; in Clojure first, and then port it to Fennel, using my implementation of lazy sequences.&lt;/p&gt;
&lt;p&gt;I will show the resulting code later in this post, but first, let&amp;rsquo;s understand what transducers are, and how they work.&lt;/p&gt;
&lt;h2 id=&#34;transducers&#34;&gt;Transducers&lt;/h2&gt;
&lt;p&gt;First, a bit of theory.
A transducer is a function that describes the process of transformation, without knowing how exactly the thing it transforms is organized.
It is not the same as generic functions, because transducers are generic in a bit different way.&lt;/p&gt;
&lt;p&gt;For example, we all know how &lt;code&gt;map&lt;/code&gt; works in Clojure - you pass it a function and a collection, and it applies the function to each element of the collection:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map inc &lt;/span&gt;[1 2 3]) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; (2 3 4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Map&lt;/code&gt; walks through the given collection, applies the given function to each element, and puts results into a sequence.
Seems nice, and Clojure actually makes &lt;code&gt;map&lt;/code&gt; generic by transforming the given collection to a sequence before actually mapping over it.
However, this approach isn&amp;rsquo;t generic &lt;em&gt;enough&lt;/em&gt;, because there are things that can&amp;rsquo;t be transformed into a sequence in an efficient or even meaningful way.
One such thing is an asynchronous channel, and when Clojure developers were working on the &lt;a href=&#34;https://github.com/clojure/core.async&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;core.async&lt;/code&gt;&lt;/a&gt; library, they&amp;rsquo;ve realized that sequence manipulation functions are usable in the context of a channel, but reimplementing all these functions is a no-go.&lt;/p&gt;
&lt;p&gt;So how did Clojure developers solve this problem?
By decoupling the transformation process from the collection it transforms.
Here&amp;rsquo;s a helpful analogy.&lt;/p&gt;
&lt;p&gt;Imagine an airport worker, whose job is to weigh and sort the luggage before it goes into a plane.
Their basic instructions are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take a bag;&lt;/li&gt;
&lt;li&gt;Measure its weight and put a sticker on the bag;&lt;/li&gt;
&lt;li&gt;If the bag weight is bigger than X, don&amp;rsquo;t put the bag on the plane;&lt;/li&gt;
&lt;li&gt;Hand the bag over.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that this process, while can be applied to a single bag at a time, doesn&amp;rsquo;t at all specify how bags are coming to you and how they leave you.
One day bags can come to you in containers brought by a vehicle, the other day they can come on a conveyor, it doesn&amp;rsquo;t matter to you - you just &lt;strong&gt;take&lt;/strong&gt; a bag, &lt;strong&gt;weigh&lt;/strong&gt; it, put a &lt;strong&gt;sticker&lt;/strong&gt; and hand it over to another car or another conveyor.
These details should not matter, because your job remains the same, even if you take bags from different sources every day.&lt;/p&gt;
&lt;p&gt;This is, of course, an analogy, but it applies to programming pretty well.
Bags are items in the collection you&amp;rsquo;re going to &lt;code&gt;map&lt;/code&gt; a function over and then &lt;code&gt;filter&lt;/code&gt; them out.
The function is what you do with the bag, in the case of our fellow airport worker weighing bags and putting stickers.
In addition, notice that we first weigh the bag, and then filter it out immediately, in oppose to weighing all bags and then filtering them one by one.&lt;/p&gt;
&lt;p&gt;However, in a programming language, the way how items are coming to us completely depends on the collection.
And how we collect results into another collection depends on the implementation of the &lt;code&gt;map&lt;/code&gt; function.
These are two main things stopping us from describing an arbitrary transformation process, without tying ourselves to a particular collection implementation or a conversion protocol.&lt;/p&gt;
&lt;p&gt;Looking at other languages, which provide different classes for different data structures, most of the time &lt;code&gt;map&lt;/code&gt; is a method and not a function.
This way &lt;code&gt;map&lt;/code&gt; can be implemented in terms of the collection you&amp;rsquo;re mapping through, usually producing the same collection as a result, because this method knows how to map a function over this particular collection implementation.&lt;/p&gt;
&lt;p&gt;Methods do not fly in functional languages, so another approach, some languages take is to provide different implementations of &lt;code&gt;map&lt;/code&gt; functions via namespaces.
For example, Elixir has a &lt;code&gt;map&lt;/code&gt; function implemented for lists and another implementation for streams:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--elixir-example&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-elixir&#34; data-lang=&#34;elixir&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# Enum versions of map and filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(1)&amp;gt; (0..3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Enum&lt;/span&gt;.map(&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt;(x) -&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#{&lt;/span&gt;x&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;); x + 1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Enum&lt;/span&gt;.filter(&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt;(x) -&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#{&lt;/span&gt;x&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;); rem(x, 2) != 0 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;List&lt;/span&gt;.first)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;# Stream versions of map and filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iex(2)&amp;gt; (0..3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Stream&lt;/span&gt;.map(&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt;(x) -&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#{&lt;/span&gt;x&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;); x + 1 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Stream&lt;/span&gt;.filter(&lt;span style=&#34;font-weight:bold&#34;&gt;fn&lt;/span&gt;(x) -&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;IO&lt;/span&gt;.puts(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;#{&lt;/span&gt;x&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;); rem(x, 2) != 0 &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Enum&lt;/span&gt;.to_list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         |&amp;gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;List&lt;/span&gt;.first)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;map 3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filter 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;&lt;a href=&#34;#code-snippet--elixir-example&#34;&gt;Code Snippet 1&lt;/a&gt;:&lt;/span&gt;
  Elixir approach to the problem
&lt;/div&gt;
&lt;p&gt;The difference is quite substantial, as streams apply function composition to each element one by one, (similarly to how our airport worker does) whereas enumerations are fully traversed by &lt;code&gt;map&lt;/code&gt; first and only then the result is being passed to &lt;code&gt;filter&lt;/code&gt;.
This distinction is possible thanks to different implementations of &lt;code&gt;map&lt;/code&gt;, but be it a method of a specific class, or a namespaced function that&amp;rsquo;s exactly what Clojure developers wanted to avoid.
So transducers were created.&lt;/p&gt;
&lt;h3 id=&#34;understanding-transducers&#34;&gt;Understanding transducers&lt;/h3&gt;
&lt;p&gt;To understand transducers, we first need to understand what &lt;code&gt;map&lt;/code&gt; essentially does and how we can abstract it away from both the input collection and the result it produces.
It may seem obvious: &lt;code&gt;map&lt;/code&gt; applies a function to &lt;strong&gt;each&lt;/strong&gt; element of a &lt;strong&gt;collection&lt;/strong&gt; and &lt;strong&gt;puts&lt;/strong&gt; the result into a new &lt;strong&gt;collection&lt;/strong&gt;.
I&amp;rsquo;ve marked important things in bold because if we think about these a bit, we&amp;rsquo;ll see that there are some concrete actions that the map function performs, which should be abstracted away.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s implement &lt;code&gt;map&lt;/code&gt; in terms of &lt;code&gt;reduce&lt;/code&gt;.
This function is actually very similar to how &lt;code&gt;mapv&lt;/code&gt; is implemented in Clojure, except we&amp;rsquo;ve left out some optimizations:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A version of `map` that uses `reduce` to traverse the collection and
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  build the result.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))) [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ^       ^                        ^            ^        ^  ^&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |       |                        |            |        |  |&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |       |                        |            |        |  `Collection to iterate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |       |                        |            |        `Collection to put results&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |       |                        |            `Function that produces the result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |       `A reducing function that`knows how to put elements to result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; `This is how we get a collection element one by one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;reduce&lt;/code&gt; takes care of how to traverse the collection, and the &lt;code&gt;reducer&lt;/code&gt; function takes care of how to put elements to the result.
It may seem that we&amp;rsquo;ve decoupled these steps from &lt;code&gt;map&lt;/code&gt; but we&amp;rsquo;ve just moved them into another place.
More than that, if we were to implement &lt;code&gt;filter&lt;/code&gt; this way we would have to put the logic, that decides what elements are going to be left out, into an anonymous function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filterr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;A version of `filter` that uses `reduce` to traverse the collection
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  and build the result.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)) [] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; ^                   ^&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |                   |&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; |                   `Logic that decides whether the value will be left out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; `generic way to iterate through a collection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice, that both &lt;code&gt;mapr&lt;/code&gt; and &lt;code&gt;filterr&lt;/code&gt; share a lot of structure, the only difference here is how to put the resulting value into the collection.
This should give us a hint on how we can abstract this away.
And given that Clojure is functional, we can write functions that accept other functions and return new functions, which will provide a generic way of how to put the result into a collection:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--simplified-transducers&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-transducer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducer&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter-transducer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pred&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducer&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pred&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This isn&amp;rsquo;t what a transducer really is like, but a first real step towards them.
The key point here is that now, we can describe a reducing process without knowing how to put the modified item into the resulting collection (or channel, or socket, or whatever).
The only thing we need to implement for collection now is &lt;code&gt;reduce&lt;/code&gt; or some other function that has the same interface as &lt;code&gt;reduce&lt;/code&gt;.
This is how we can use these prototype transducers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;incrementer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; a function that knows how to increment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/incrementer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;incrementer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; teaching `incrementer` how to put elements to the result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user/map-transducer/fn--5698/fn--5699&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;incrementer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;) [] [1 2 3]) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; using this transducer in `reduce`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 3 4]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;) [] [1 2 3]) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; same for `filter-transducer`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1 3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So what happens here is that when we call &lt;code&gt;map-transducer&lt;/code&gt; and pass it a function &lt;code&gt;inc&lt;/code&gt; it returns a function, that accepts the &lt;code&gt;reducer&lt;/code&gt; also known as the reducing function of just &lt;code&gt;rf&lt;/code&gt; for short.
We then call this function, passing it the reducing function &lt;code&gt;conj&lt;/code&gt; and get another function, that accepts the results so far, and the element to process.
This function then calls &lt;code&gt;inc&lt;/code&gt;, which we&amp;rsquo;ve supplied in the first step, on the element, and uses &lt;code&gt;conj&lt;/code&gt; to put the resulting value to &lt;code&gt;result&lt;/code&gt;.
In other words, by passing &lt;code&gt;inc&lt;/code&gt; and &lt;code&gt;conj&lt;/code&gt; to the transducer we&amp;rsquo;ve basically constructed &lt;code&gt;(fn [result value] (conj res (inc value)))&lt;/code&gt; function, that is then used by &lt;code&gt;reduce&lt;/code&gt;.
Here&amp;rsquo;s a demonstration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;) [] [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 3 4]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))) [] [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2 3 4]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s basically what transducers are all about!
They&amp;rsquo;re just a composition of functions, that produces the final transformation function, that acts as a single step over the given collection.
And the amazing part of such design is that transducers can be composed with other transducers:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;code-snippet--composition-expanded&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              [] [1 2 3 4 5 6])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[3 5 7]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]       &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; above is essentially the same as this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; function composition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              [] [1 2 3 4 5 6])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[3 5 7]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may be a little hard to process, but don&amp;rsquo;t worry, I will go into details after we complete the implementation of transducers, as we&amp;rsquo;re not yet finished.&lt;/p&gt;
&lt;h3 id=&#34;completing-transducers&#34;&gt;Completing transducers&lt;/h3&gt;
&lt;p&gt;Most transducers don&amp;rsquo;t have any intermediate state, but &lt;em&gt;some&lt;/em&gt; do.
For example, the &lt;code&gt;partition-all&lt;/code&gt; function takes a collection and returns a list of partitions of elements from this collection.
The transducer, which is returned by this function, needs to store elements inside an array, and only after the current partition is filled it will append it to the result.
Seems logical, however, if the number of elements can&amp;rsquo;t be equally partitioned, some will be left over:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 3 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;8)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; a regular partition-all call&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((0 1 2) (3 4 5) (6 7))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all-transducer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Our naive implementation of `partition-all` as a transducer.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;volatile!&lt;/span&gt; [])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vswap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)     &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; building the partition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p*&lt;/span&gt; @&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vreset!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; [])        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; clearing the partition storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p*&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; adding the partition to the result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; returning result as is, if the partition is not yet complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                )))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/partition-all-transducer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all-transducer&lt;/span&gt; 3) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;) [] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;8))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[0 1 2] [3 4 5]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can see that in the case of our implementation, only complete partitions were added to the result, yet there should be an additional incomplete partition, as shown by the direct &lt;code&gt;partition-all&lt;/code&gt; call.
This is because our transducer is missing a so-called &lt;strong&gt;completion&lt;/strong&gt; step:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all-transducer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;volatile!&lt;/span&gt; [])]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;]                       &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; completion arity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;pos? &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; @&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]                 &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; reduction arity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vswap!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;@&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p*&lt;/span&gt; @&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vreset!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;p*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here I&amp;rsquo;ve added another arity, that must be called after the reduction process is complete.
This arity checks if the array we&amp;rsquo;ve used to store the incomplete partition is not empty.
If it&amp;rsquo;s not, it means that there are some leftovers, that we need to add to the result.
So it calls &lt;code&gt;reducing-function&lt;/code&gt; with this array, otherwise it will call &lt;code&gt;reducing-function&lt;/code&gt; with &lt;code&gt;result&lt;/code&gt; only, propagating completion step down the line.
Invoking this arity after &lt;code&gt;reduce&lt;/code&gt; completed, we can see that all partitions are present:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all-transducer&lt;/span&gt; 3) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; [] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;8))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; complete step&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[0 1 2] [3 4 5] [6 7]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Our &lt;code&gt;reduce&lt;/code&gt; example has become way too verbose, and there&amp;rsquo;s also a potential for error if our transducer leaked from this scope and someone else used it after it was completed.
Notice that I&amp;rsquo;ve forgotten to clear the volatile &lt;code&gt;p&lt;/code&gt; in the completion step, and if someone else calls this particular function again, these leftover elements will be added to the result again.
(Try to achieve that.)&lt;/p&gt;
&lt;p&gt;Therefore, Clojure abstracts the process of finalizing a transducer into a function, conventionally called &lt;code&gt;transduce&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;init&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;init&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ret&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s one additional arity that can be added to our transducer implementation, which is used for initialization, done by calling the reducing function without arguments.
This arity takes zero arguments, and it is optional, as not all reducing functions can come up with a meaningful initialization process, but it&amp;rsquo;s better to supply it than not.
So a complete implementation of the &lt;code&gt;map-transducer&lt;/code&gt; function is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-transducer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ([]                               &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;]                         &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;]                   &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; step&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inputs&lt;/span&gt;]          &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; step with multiple inputs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reducing-function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inputs&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  A complete implementation of a mapping transducer
&lt;/div&gt;
&lt;p&gt;And that&amp;rsquo;s it!
This is a complete implementation of a transducer.
Clojure provides this as an additional arity of &lt;code&gt;map&lt;/code&gt; where you only supply a function, without the collection, thus we don&amp;rsquo;t even need a separate function for this, it was merely for demonstration purposes.&lt;/p&gt;
&lt;p&gt;If you look back at the &lt;a href=&#34;#code-snippet--elixir-example&#34;&gt;Elixir example&lt;/a&gt;, you can see that when &lt;code&gt;Stream&lt;/code&gt; implementations of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; are used, each function is applied in quick succession, opposed to &lt;code&gt;Enum&lt;/code&gt; version, where &lt;code&gt;map&lt;/code&gt; is applied first, and then the result is &lt;code&gt;filter&lt;/code&gt;&amp;lsquo;ed as a whole.
With transducers, we just implemented, or with ones available to us in Clojure we can do exactly the same:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;transduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; map 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; filter 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; =&amp;gt; 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, I should mention that it&amp;rsquo;s a bit stretched example.
The lazy composition of sequences in the first snippet &lt;em&gt;should&lt;/em&gt; behave similarly to the second because when we&amp;rsquo;re mapping a function in a lazy way we don&amp;rsquo;t consume the whole sequence, we only produce a new one, that knows how to construct itself based on the previous one.
And if we then filter this mapped sequence, we again construct a new sequence, that knows how to build itself lazily.
So, in an ideal world, the first example should also give us &lt;code&gt;map,filter,map,filter&lt;/code&gt; kind of composition, but unfortunately, it is somewhat slow, so Clojure uses chunking, and lazy sequences can compute up to 32 elements upfront.
This isn&amp;rsquo;t the case for Elixir example, &lt;code&gt;Enum.map&lt;/code&gt; &lt;a href=&#34;https://github.com/elixir-lang/elixir/blob/4f5e9f467da4abb86fa20a77979cb5bd96f3572f/lib/elixir/lib/enum.ex#L1655-L1663&#34; target=&#34;_blank&#34;&gt;is eager&lt;/a&gt; (the &lt;a href=&#34;https://github.com/erlang/otp/blob/acc936656e2cbe92185c934207cc9e85707705c9/lib/stdlib/src/lists.erl#L1313-L1322&#34; target=&#34;_blank&#34;&gt;Erlang module&lt;/a&gt; is also eager), and will produce fully realized sequences.
Streams in Elixir are lazy, and perhaps their composition is what we would have for lazy sequences in Clojure if there was no chunking, but in our case transducers show the difference in composition a bit clearer.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s really understand how transducers work.&lt;/p&gt;
&lt;h3 id=&#34;understanding-the-inverse-order-in-comp-and-how-transducers-are-composed&#34;&gt;Understanding the &lt;em&gt;inverse&lt;/em&gt; order in &lt;code&gt;comp&lt;/code&gt; and how transducers are composed&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;transduce&lt;/code&gt; call may have seemed a bit &lt;i&gt;comp&lt;/i&gt;licated because of &lt;code&gt;comp&lt;/code&gt;, but here&amp;rsquo;s a nice trick I&amp;rsquo;ve found.
Simply remember, that the order of transducers in &lt;code&gt;comp&lt;/code&gt; is exactly the same as the order of calls in the &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; macro.
However, it may seem counter-intuitive, because usually functions in &lt;code&gt;comp&lt;/code&gt; are applied in the &lt;em&gt;reverse&lt;/em&gt; order, e.g.:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; expressions are aligned for clarity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;d&lt;/span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In other words, even though functions are provided in order &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;d&lt;/code&gt;, the call order will be &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;.
And in the case of transducers the composition works the same way, it&amp;rsquo;s just we have one extra step after we&amp;rsquo;ve passed the reducing function.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;ve &lt;a href=&#34;#code-snippet--composition-expanded&#34;&gt;demonstrated&lt;/a&gt; in this example, the composition basically is engineered in such a way that it kinda inverses its order twice.
The first inversion happens after we compose functions, and the second inversion happens when we pass the reducing function.
Let&amp;rsquo;s use the substitution model, sometimes referred to as &lt;a href=&#34;https://en.wikipedia.org/wiki/Evaluation_strategy#Normal_order&#34; target=&#34;_blank&#34;&gt;normal order evaluation&lt;/a&gt; to see why this happens.&lt;/p&gt;
&lt;p&gt;Substitution here basically means that before we do any reduction, we expand all forms until they only contain primitives.
This is done by substituting names with expressions they refer to.
For example, given these three functions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;square&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-squares&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;square&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;square&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can walk through the &lt;code&gt;(sum-squares (add 1 1) (add 1 2))&lt;/code&gt; expression, and see how it will be evaluated in normal order, and how it differs from applicative order:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Normal order&lt;/th&gt;
&lt;th&gt;Applicative order&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(sum-squares (add 1 1) (add 1 2))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(sum-squares (add 1 1) (add 1 2))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(sum-squares (+ 1 1) (+ 1 2))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(sum-squares (+ 1 1) (+ 1 2))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(+ (square (+ 1 1)) (square (+ 1 2)))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(sum-squares 2 3)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(+ (* (+ 1 1) (+ 1 1)) (* (+ 1 2) (+ 1 2)))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(+ (square 2) (square 3))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(+ (* 2 2) (* 3 3))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(+ (* 2 2) (* 3 3))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(+ 4 9)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(+ 4 9)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;13&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;13&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Notice, that in normal order &lt;code&gt;(+ 1 1)&lt;/code&gt; and &lt;code&gt;(+ 1 2)&lt;/code&gt; are executed twice, because all substituting happens before any reduction.
In applicative order, reduction happens before substituting, so every expression is computed only once.
Applicative order is more in line with real evaluation rules, but it&amp;rsquo;s harder to see what&amp;rsquo;s happening when we compose things, so I&amp;rsquo;ll use the normal order to show how transducers are composed.&lt;/p&gt;
&lt;p&gt;With this in mind, let&amp;rsquo;s try to walk through the following expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;filter-transducer&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we need to substitute &lt;code&gt;map-transducer&lt;/code&gt; and &lt;code&gt;filter-transducer&lt;/code&gt; with their (&lt;a href=&#34;#code-snippet--simplified-transducers&#34;&gt;simplified&lt;/a&gt;) implementations:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)))) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, let&amp;rsquo;s substitute &lt;code&gt;f&lt;/code&gt; with &lt;code&gt;inc&lt;/code&gt; and &lt;code&gt;odd?&lt;/code&gt; and get rid of function calls, substituting them with anonymous functions that accept &lt;code&gt;rf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, knowing that composition of functions &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;g&lt;/code&gt; is &lt;code&gt;(fn [x] (f (g x)))&lt;/code&gt; we can substitute &lt;code&gt;comp&lt;/code&gt; with this expression, and then substitute &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;g&lt;/code&gt; in this expression with our functions from the previous step:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that according to composition rules, &lt;code&gt;odd?&lt;/code&gt; should be executed first, and &lt;code&gt;inc&lt;/code&gt; would follow it, but we&amp;rsquo;re not done composing yet.
Let&amp;rsquo;s substitute &lt;code&gt;x&lt;/code&gt; for &lt;code&gt;conj&lt;/code&gt; and remove the function call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;conj&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can now substitute &lt;code&gt;rf&lt;/code&gt; for &lt;code&gt;conj&lt;/code&gt; in the innermost function call, and remove the innermost function that accepts &lt;code&gt;rf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rf&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, we can substitute outer &lt;code&gt;rf&lt;/code&gt; with the entire inner function body, and remove another call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As the last step, we&amp;rsquo;re substituting the inner function&amp;rsquo;s &lt;code&gt;value&lt;/code&gt; to &lt;code&gt;(inc value)&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt; to &lt;code&gt;result&lt;/code&gt; to eventually get:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;conj &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;result&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The final function that will be executed by &lt;code&gt;reduce&lt;/code&gt;, which is just an ordinary two-argument function!
And as you can see &lt;code&gt;inc&lt;/code&gt; happens before &lt;code&gt;odd?&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So yes, the order in &lt;code&gt;comp&lt;/code&gt; may seem inverse, as &lt;code&gt;inc&lt;/code&gt; and &lt;code&gt;odd&lt;/code&gt; appear in a logical order, but thanks to how the whole composition process evolves, this logical order can be preserved in the resulting function.
I hope that with this substitution model you can now understand the whole composition process of transducers, which is not a trivial process by any means.
But I&amp;rsquo;m actually amazed by how this simple idea achieves such a complete abstraction that can be used in all kinds of transformation contexts.&lt;/p&gt;
&lt;p&gt;Speaking of transduceable contexts, let&amp;rsquo;s implement one!&lt;/p&gt;
&lt;h2 id=&#34;implementing-sequence-transduceable-context&#34;&gt;Implementing &lt;code&gt;sequence&lt;/code&gt; transduceable context&lt;/h2&gt;
&lt;p&gt;Now we&amp;rsquo;re ready to implement &lt;code&gt;sequence&lt;/code&gt; in Clojure, without direct Java interop.
First, let&amp;rsquo;s remember what &lt;code&gt;reduce&lt;/code&gt; does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accepts a function, initial value, and a collection;&lt;/li&gt;
&lt;li&gt;Gets an element of a collection and passes the initial value and the element to the reducing function;&lt;/li&gt;
&lt;li&gt;The reducing function returns the current result;&lt;/li&gt;
&lt;li&gt;The result is then passed to the reducing function alongside the next element from the collection;&lt;/li&gt;
&lt;li&gt;Once the collection is exhausted, the result is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thus, &lt;code&gt;reduce&lt;/code&gt; can be written as an ordinary loop.
However, &lt;code&gt;sequence&lt;/code&gt; is lazy, therefore we can&amp;rsquo;t just loop through the collection, but thankfully, lazy sequences can be recursive.
And, there&amp;rsquo;s another problem, we must append each element to the sequence we&amp;rsquo;re producing, but we also need to check if we&amp;rsquo;ve actually finished, or if we need to skip the element because it is filtered out.
And we need to call the completion step somewhere.&lt;/p&gt;
&lt;p&gt;Though, if you think about it, we don&amp;rsquo;t need for our transducer to actually append elements to a collection, it can merely do the transformation, and since we know what kind of collection we&amp;rsquo;re building, we can build it &lt;em&gt;later&lt;/em&gt;.
With this approach, we can check the result of a transducer on each step and act accordingly.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s finalize the transducer with a reducing function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; lazy loop?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may seem that we&amp;rsquo;re using &lt;code&gt;cons&lt;/code&gt; here because we&amp;rsquo;re building a sequence, but it&amp;rsquo;s not.
We could actually use anything, like &lt;code&gt;conj&lt;/code&gt; or even a function that returns something that we can later distinguish from other values.
In &lt;code&gt;cons&lt;/code&gt; call, we have to reverse arguments though, because &lt;code&gt;cons&lt;/code&gt; adds the second argument to a list, provided as a first argument.
And &lt;code&gt;completing&lt;/code&gt; simply adds a completion step that just returns the value it&amp;rsquo;s been given, in other words, we could write it as &lt;code&gt;(fn ([a] a) ([a b] (cons b a)))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s figure out how to loop through the collection.
We can start with an ordinary loop and then convert it to recursion, adding laziness as the last step.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; ()]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s try it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(2 3 4)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2) [1 2 3 4 5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([1 2] [3 4])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/sequence&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2) [1 2 3 4 5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([1 2] [3 4] [5])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Seems to work, but we&amp;rsquo;re missing the completion step (hence no incomplete partition in the result), so let&amp;rsquo;s add it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; ()]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))]        &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2) [1 2 3 4 5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([5] [1 2] [3 4])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Oops, remember, that we&amp;rsquo;re using &lt;code&gt;cons&lt;/code&gt; and we can&amp;rsquo;t really call &lt;code&gt;f&lt;/code&gt; with &lt;code&gt;res&lt;/code&gt; as a completion step, because our reducing function doesn&amp;rsquo;t know how to build the whole collection, only how to transform a single element.
Instead, we have to call it with &lt;code&gt;nil&lt;/code&gt; as before, and &lt;code&gt;concat&lt;/code&gt; it with the result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; ()]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; proper completion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2) [1 2 3 4 5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([1 2] [3 4] [5])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now let&amp;rsquo;s make it recursive, by replacing &lt;code&gt;loop&lt;/code&gt; with an anonymous function, and &lt;code&gt;recur&lt;/code&gt; with actual recursion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;next &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt; ())))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2) [1 2 3 4 5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([1 2] [3 4] [5])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dorun &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;100000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Execution&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;StackOverflowError&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user/sequence$step&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;REPL&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:25&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It still seems to work, but overflows with enough elements.
Luckily, we can use &lt;code&gt;lazy-seq&lt;/code&gt; to eliminate this problem, and actually make our implementation lazy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt; ())))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dorun &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;100000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Execution&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;error&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;StackOverflowError&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;at&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user/sequence$step&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;REPL&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:1&lt;/span&gt;)&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it still throws the &lt;code&gt;StackOverflowError&lt;/code&gt;.
Why?&lt;/p&gt;
&lt;p&gt;Well, because we&amp;rsquo;re not really lazy yet.
Instead of passing the result to the next iteration of &lt;code&gt;step&lt;/code&gt;, as we did in &lt;code&gt;loop&lt;/code&gt; we should use the result of &lt;code&gt;step&lt;/code&gt; and concatenate with it.
Let&amp;rsquo;s reorganize our function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dorun &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;inc&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;100000)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now it doesn&amp;rsquo;t overflow.
However, it is not yet ready to be used, because &lt;code&gt;reduce&lt;/code&gt;, as you may know, can be terminated with &lt;code&gt;reduced&lt;/code&gt;, and some transducers, like &lt;code&gt;take&lt;/code&gt; leverage that to terminate the process.
So we need to check for &lt;code&gt;reduced?&lt;/code&gt; in our implementation.
Not only that, but we have to call the completion step on the value, returned by dereferencing the &lt;code&gt;reduced&lt;/code&gt; object, otherwise it will not be added to the resulting sequence properly.:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          ((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduced?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;deref &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; checking for early termination&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:else&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;user/sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;5)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([0 1] [2 3] [4 5] [6 7] [8 9])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;5) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;partition-all&lt;/span&gt; 2)) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;([0 1] [2 3] [4])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And we&amp;rsquo;re done!
Well, almost, &lt;code&gt;sequence&lt;/code&gt; should coerce the result to an empty sequence, and our current version will return &lt;code&gt;nil&lt;/code&gt; if the transducer never returned anything.
It&amp;rsquo;s easy enough to fix:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;xform&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;completing&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cons &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or &lt;/span&gt;((&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;cond &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduced?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;deref &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;res&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lazy-seq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:else&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;step&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rest &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;s&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ())))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  Final version of our &lt;code&gt;sequence&lt;/code&gt; transducer.
&lt;/div&gt;
&lt;p&gt;We can see that it is lazy, by using side-effecting transducers, like ones with &lt;code&gt;println&lt;/code&gt; in those:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take &lt;/span&gt;3))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 3&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 5)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 4:&lt;/span&gt;
  Notice that the output is all messed up, because the sequence started printing before it was realized, and side effects appeared during the pretty printing process, which itself is lazy.
&lt;/div&gt;
&lt;p&gt;And as you can see, our &lt;code&gt;sequence&lt;/code&gt; behaves in the same way as the &lt;code&gt;clojure.core/sequence&lt;/code&gt;, regarding laziness:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; note, infinite range&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user&amp;gt;&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;do &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.core/sequence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;comp &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;map&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;odd?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;range&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;filter &lt;/span&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I think now &lt;code&gt;sequence&lt;/code&gt; is completed, though I&amp;rsquo;ll need to test it very extensively in the future.
I&amp;rsquo;ve already tested it a lot when I was porting it to Fennel, and I think it should work correctly, looking at the code at least I don&amp;rsquo;t see anything that could go wrong.&lt;/p&gt;
&lt;h2 id=&#34;what-have-i-learned&#34;&gt;What have I learned&lt;/h2&gt;
&lt;p&gt;Implementing transduceable context, in this case, the &lt;code&gt;sequence&lt;/code&gt; function, was a nice puzzle.
I&amp;rsquo;m sure it&amp;rsquo;s not as efficient, as the &lt;code&gt;clojure.core&lt;/code&gt; version, mainly due to the use of &lt;code&gt;concat&lt;/code&gt; but I wasn&amp;rsquo;t able to come up with a better way of building the result which can be done lazily.&lt;/p&gt;
&lt;p&gt;And after actually implementing &lt;code&gt;sequence&lt;/code&gt;, porting it, and a lot of transducers to Fennel, I&amp;rsquo;ve finally figured out how they actually work, and I hope that now you understand it too!
This is why I love Clojure - the developers are putting a lot of thought into such features, and not taking shortcuts, like reimplementing all functions for data sources that can&amp;rsquo;t be transformed into sequences.
For me, it&amp;rsquo;s a really practical language, with a lot of tools that can enhance the programming experience, and make it fun.&lt;/p&gt;
&lt;p&gt;Of course, if you have any questions, feel free to email me, and I&amp;rsquo;ll try to answer them, and maybe update the post for future readers.
This topic is a bit complicated, so I hope it was not a boring post.
Thanks for reading!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I actually like this approach to learning.
Usually, I&amp;rsquo;m not reading how a thing is implemented, and instead trying to figure out everything myself.
This unfortunately doesn&amp;rsquo;t produce the greatest results, as a lot of stuff I&amp;rsquo;m trying to learn this way has a lot of research put into it, and I basically try to reimplement a thing only based on assumptions and observations.
Nevertheless, I&amp;rsquo;m satisfied with the process, and in the end, if I got something working, I feel happy, and even more so, when I&amp;rsquo;ve got some concepts exactly right.
I&amp;rsquo;m not suggesting that this is a superior way to learn, but it is at least very enjoyable for me personally.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Understanding transducers&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 13 Aug 2022 16:03:00 +0300</pubDate>
    </item><item>
      <title>Counting From Zero</title>
      <link>https://andreyor.st/posts/2022-07-29-counting-from-zero/</link>
      <guid>https://andreyor.st/posts/2022-07-29-counting-from-zero/</guid>
      <description>&lt;p&gt;I often hear this phrase: &amp;ldquo;programmers are counting from zero&amp;rdquo;.
Not so long ago I actually decided to check if it is true and asked some programmers I know to count to ten out loud.&lt;/p&gt;
&lt;p&gt;None of them counted from zero.&lt;/p&gt;
&lt;p&gt;Well, this phrase is usually brought up when discussing various programming languages, which share the common idiom - zero-based array indexing.
In this context, yeah, many programmers have to count from zero, except I&amp;rsquo;ve never heard someone refer to the first element of an array as the &amp;ldquo;zeroth element&amp;rdquo;.
So, even in languages that are zero-indexed people still refer to array elements by their natural indexes, and only specify zero-based indexes when they refer to an actual code that accesses the array element.
Yet, zero-based indexing is used in a lot of programming languages, and many programmers think that this is the case for all languages, mainly because it was the same for all languages they&amp;rsquo;ve tried, but it&amp;rsquo;s actually not the case.
Though such languages are rare, so this assumption can be understood.&lt;/p&gt;
&lt;p&gt;As you may know from my other posts, I often program in the Fennel language, which then compiles itself to Lua.
And Lua is one of these languages, which starts counting from one.
This throws off many programmers, and I often see in the &lt;code&gt;#fennel&lt;/code&gt; IRC channel messages, asking if Fennel fixes this design misfeature of Lua.
Fennel does fix a lot of design misfeatures of Lua, but one-based indexing is not one of them.
&lt;em&gt;Kinda&lt;/em&gt;, I&amp;rsquo;ll talk about it a bit later.&lt;/p&gt;
&lt;p&gt;But first, let’s figure out why some low-level languages use zero-based indexing.&lt;/p&gt;
&lt;h2 id=&#34;arrays-and-memory&#34;&gt;Arrays and memory&lt;/h2&gt;
&lt;p&gt;Languages like C are quite efficient with memory, and also kinda unsafe because of that.
For instance, arrays in C are just pointers to a specific memory location, and the very start of the array matches its first element.
So the index of the array in C is actually a memory offset, and zero offset matches the start of the block of memory.
Then, to have very quick access to array elements, the index is added to the address of the array, and we get a new memory address that is just dereferenced for value access.
Which is &lt;strong&gt;very fast&lt;/strong&gt;.
The &lt;code&gt;arr[10]&lt;/code&gt; syntax is nothing but a sugar over &lt;code&gt;*(arr+10)&lt;/code&gt;, as demonstrated by this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;arr[4]: %d&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, arr[4]); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// prints arr[4]: 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*(arr+4): %d&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, *(arr + 4)); &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// prints *(arr+4): 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;C actually increments addresses differently, so &lt;code&gt;+&lt;/code&gt; on a pointer works not the same as plus on the integer, but that’s beside the point.
The point is, that arrays in C are contiguous segments of memory, which programmers took advantage of for a long time.
And a lot of languages were influenced by C, due to its popularity, or the fact that these languages are simply implemented in C.
But high-level languages may, or may not use the same memory layout for their arrays.&lt;/p&gt;
&lt;p&gt;The key takeaway here is that there are two fundamentally different approaches to data structures - ones that are memory mapped, and others that aren&amp;rsquo;t.
If your language has memory-mapped data structures, like arrays in C, then yes, zero-based indexing is probably what you want, but it&amp;rsquo;s not mandatory.
I&amp;rsquo;m saying it&amp;rsquo;s not mandatory because it really doesn&amp;rsquo;t matter that much, a compiler may convert indexes to offset mapping 1 to 0 when accessing memory-mapped data, so you still can choose to use one-based indexing if you&amp;rsquo;re developing such a language.
Especially, if you have non-memory-mapped data structures, that are sequential and can be indexed, like Clojure vectors that are based on persistent &lt;a href=&#34;https://en.wikipedia.org/wiki/Hash_array_mapped_trie&#34; target=&#34;_blank&#34;&gt;hash-array-mapped-tries&lt;/a&gt;.
Thus, I&amp;rsquo;d say that zero-based indexing is not a requirement but a tradition, that most programmers don&amp;rsquo;t think about.&lt;/p&gt;
&lt;h2 id=&#34;why-lua-tables-use-one-based-indexing&#34;&gt;Why Lua tables use one-based indexing&lt;/h2&gt;
&lt;p&gt;Most languages, despite being high level or low level, use zero-based indexing, even if it doesn&amp;rsquo;t make sense in the context of the actual implementation of the data structure.
In Lua, however, there are no arrays, only tables, and until a certain point tables &lt;a href=&#34;http://www.lua.org/source/4.0/lobject.h.html#Hash&#34; target=&#34;_blank&#34;&gt;were not storing data in one contiguous block&lt;/a&gt; for integer keys.
And AFAIK it was one-based because the developers thought that this is easier to understand for non-programmers.&lt;/p&gt;
&lt;p&gt;Table implementation &lt;a href=&#34;http://www.lua.org/source/5.4/lobject.h.html#Table&#34; target=&#34;_blank&#34;&gt;has changed&lt;/a&gt; since, and includes array part storing sequential integer keys, mainly for optimization purposes, but because tables are &lt;em&gt;not arrays&lt;/em&gt; the indexing was kept one-based.
And because of a combined nature, Lua&amp;rsquo;s tables can be indexed from any integer key:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t = {[-1]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, [0]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(t[-1]) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(t[1])  &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This only proves the point that in a high-level language you can index things however you want if the data structure supports it.
In the case of this table, the hash part stores keys &lt;code&gt;-1&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt;, and the array part stores the rest of the values in a contiguous block of memory.&lt;/p&gt;
&lt;p&gt;This may seem like a huge foot-gun because you never know what keys are in the table, and how to iterate over it.
If you want to iterate, as you would in C, then yes, the problem is real.
Lua does support numerical loops, so if you know the minimal key in your table, and table length, you can do it like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; t = {[-1]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, [0]=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i=-1,#t &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(t[i])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As a small benefit, table length, obtained with &lt;code&gt;#&lt;/code&gt; operator here, always matches&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; the last integer key.
E.g. the length of this table &lt;code&gt;{&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;}&lt;/code&gt; is &lt;code&gt;3&lt;/code&gt;, so you can just iterate over it by indexes from &lt;code&gt;1&lt;/code&gt; to &lt;code&gt;3&lt;/code&gt; inclusively, not to &lt;code&gt;#t-1&lt;/code&gt;, as you would have to do in zero-indexed language.&lt;/p&gt;
&lt;p&gt;But the thing is - you likely won&amp;rsquo;t be doing such loops, because these loops only make sense in the context of partial iteration, and tables in Lua almost never iterated partially.
And this actually applies to many other high-level languages, that have functions like &lt;code&gt;map(f, coll)&lt;/code&gt; and &lt;code&gt;filter(f, coll)&lt;/code&gt; - if you want to partially iterate an array you&amp;rsquo;ll likely &lt;code&gt;filter&lt;/code&gt; it first.
Lua doesn&amp;rsquo;t have such functions, but it still has a generic way to iterate over tables without thinking about indexes, as it provides two functions that return iterators over the table: &lt;code&gt;pairs&lt;/code&gt; and &lt;code&gt;ipairs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; k,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; pairs {a=1, b=2, c=3, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;} &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(k, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1 foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2 bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- c 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- a 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- b 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  &lt;code&gt;pairs&lt;/code&gt; traverses array part first, and then hash part in arbitrary order.
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; i,v &lt;span style=&#34;font-weight:bold&#34;&gt;in&lt;/span&gt; ipairs {foo=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;bar&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;} &lt;span style=&#34;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(i, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 1 a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 2 b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 3 c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  &lt;code&gt;ipairs&lt;/code&gt; only traverses the array part, ignoring the hash part
&lt;/div&gt;
&lt;p&gt;These functions are fundamental ways to traverse tables in Lua, and the reason one-based indexing is not a huge problem.
It is unlikely that you&amp;rsquo;ll be using table indexing with numerical indexes, because data that has to be taken out usually comes in associative tables, and the array part usually is traversed as a whole.
Still, if you do want to index sequential tables, you&amp;rsquo;ll have to remember that indexing starts from 1 in Lua.
Here&amp;rsquo;s a function in Lua that sums the first three values of a table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum_three&lt;/span&gt;(t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a, b, c = t[1], t[2], t[3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; a + b + c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sum_three({4, 5, 6, 7}) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- 15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A programmer not familiar with Lua indexed might make a mistake here, and write &lt;code&gt;local a, b, c = t[0], t[1], t[2]&lt;/code&gt;, thus getting &lt;code&gt;nil + 4 + 5&lt;/code&gt; as a result.
Fennel, on the other hand, while not changing the indexing of the table, actually helps you not to make mistakes by providing a feature, called destructuring.
It avoids this problem by not using indexes at all - here&amp;rsquo;s the same function in Fennel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [4 5 6 7]) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; 15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;(local [a b c] t)&lt;/code&gt; is a destructuring syntax, which is also known as pattern matching in languages like Erlang or Elixir, except it doesn&amp;rsquo;t do actual pattern matching here, only &lt;em&gt;pattern binding&lt;/em&gt;.
What it essentially does is, it looks at the shape of provided data, &lt;code&gt;[a b c]&lt;/code&gt; in this case, and understands that in this case &lt;code&gt;t&lt;/code&gt; should be treated as an array, where each of the names are bound to the respecting elements from that array.
It is compiled to the same kind of code, as we&amp;rsquo;ve manually written in Lua before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum_three&lt;/span&gt;(t)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; a = t[1]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; b = t[2]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; c = t[3]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (a + b + c)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not as pretty as handwritten Lua code, but saves you the trouble of knowing what indexes to use, as now it is an internal thing.
This syntax is supported everywhere in Fennel where names are bound, for example in the function argument list, so the function can be rewritten more idiomatically like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The compiled Lua is again essentially the same as the one from the above.
You might wonder how to skip some elements in the array then?
You simply ignore those by using a &lt;code&gt;_&lt;/code&gt; as a name in the binding syntax:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fennel&#34; data-lang=&#34;fennel&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-some&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-some&lt;/span&gt; [1 2 3 4 5 6 7]) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; (+ 4 5 7)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, if you need to get the 489th element of the array, this won&amp;rsquo;t really scale, and at this point, you might want to use indexes, but I doubt that this will happen too often for you.
At least I&amp;rsquo;ve never needed to do that, or even to skip elements with &lt;code&gt;_&lt;/code&gt; like above, for that matter.&lt;/p&gt;
&lt;p&gt;The fun part is that Fennel shares its syntax with Clojure to some extent, and Clojure, being a JVM-hosted language, uses zero-based indexing for its arrays.
And thanks to the fact that destructuring is supported by both languages, I never get confused about what indexing to use when I switch between the two languages very frequently.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Clojure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Fennel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sum-three&lt;/span&gt; [1 2 3])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  spot the difference
&lt;/div&gt;
&lt;p&gt;So while Fennel didn&amp;rsquo;t &lt;em&gt;fix&lt;/em&gt; the indexing, it surely made it less of a problem (especially for those coming from Clojure).&lt;/p&gt;
&lt;h2 id=&#34;so-what-was-this-all-about&#34;&gt;So what was this all about&lt;/h2&gt;
&lt;p&gt;What I wanted to say by this post is that zero-based indexing is not really something that is often thought about too much by programmers nowadays.
We accept that most languages use it, even if it doesn&amp;rsquo;t make sense in the context of the data structures it uses, and new languages usually stick to the same approach to avoid confusion.
And, I also think, that if a language steps out of the line and tries to use one-based indexing, it may have a much harder adoption, due to programmers freaking out and making mistakes because of this choice.&lt;/p&gt;
&lt;p&gt;Personally, if I were to develop a language for myself that doesn&amp;rsquo;t use memory-mapped data structures, I&amp;rsquo;d go for one-based indexing, because it makes more sense to me.
And if I later added C-like arrays, I&amp;rsquo;d still keep the 1-based indexing for them, because it&amp;rsquo;s just the compiler&amp;rsquo;s internal knowledge of how the data structure is implemented.
And one small benefit of doing iteration over indexes and not subtracting one from the array length is also kinda nice :)&lt;/p&gt;
&lt;p&gt;Though, if I wanted my language to be more widely adopted I&amp;rsquo;d consider using zero-based indexing.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;It&amp;rsquo;s not always the case if the table has gaps, but that&amp;rsquo;s a different story.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Counting From Zero&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 29 Jul 2022 09:34:00 +0300</pubDate>
    </item><item>
      <title>Spam Rant</title>
      <link>https://andreyor.st/posts/2022-07-26-spam-rant/</link>
      <guid>https://andreyor.st/posts/2022-07-26-spam-rant/</guid>
      <description>&lt;p&gt;Who doesn&amp;rsquo;t dislike spam?
Well, apparently &lt;a href=&#34;https://www.ted.com/talks/james_veitch_this_is_what_happens_when_you_reply_to_spam_email&#34; target=&#34;_blank&#34;&gt;this guy loves it&lt;/a&gt;, but in a kind of special way.
I definitively don&amp;rsquo;t like spam, even a &lt;em&gt;clever one&lt;/em&gt;, but unfortunately, we all have to deal with it to some extent.
This is a rant on spam because I was just fed up with it once again.&lt;/p&gt;
&lt;p&gt;There are several categories of spam in my life:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;E-Mail spam.&lt;/li&gt;
&lt;li&gt;Spam calls.&lt;/li&gt;
&lt;li&gt;SMS spam.&lt;/li&gt;
&lt;li&gt;Promoted spam.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think you all are familiar with the first three categories, and as much as I dislike these, there&amp;rsquo;s not much to say about them.&lt;/p&gt;
&lt;p&gt;At least, the first two are kind of easy to deal with.
I don&amp;rsquo;t read 99% of e-mails that end up in my spam folder, conveniently managed for me by GMail.
While I don&amp;rsquo;t really like GMail, and rather move to a self-hosted mail, Google does a pretty decent job at tracking spam, even with all smart features being &amp;ldquo;disabled&amp;rdquo;.
I never answer calls that aren&amp;rsquo;t on my contact list, unless I&amp;rsquo;m waiting for some kind of delivery.
This is an easy fix because you can make your phone only make a sound when someone from your contact list is calling you, or even writing a message.&lt;/p&gt;
&lt;p&gt;But the last two categories are hard to deal with.&lt;/p&gt;
&lt;h2 id=&#34;sms-spam&#34;&gt;SMS spam&lt;/h2&gt;
&lt;p&gt;SMS is &lt;a href=&#34;https://en.wikipedia.org/wiki/SMS#SMS_today&#34; target=&#34;_blank&#34;&gt;still widely used&lt;/a&gt; for delivering various kinds of information to people.
And for some reason, it is considered an &lt;em&gt;official&lt;/em&gt; communication channel by a lot of people.
For example, when you need to secure an operation in your bank, it will likely send you an SMS with a confirmation code.
At least this was the case until some years ago when most banks I use switched to using their respecting application on Android/iOS, which is used to show the code now.&lt;/p&gt;
&lt;p&gt;But still, some companies may send you such codes from time to time, and that&amp;rsquo;s basically the only useful case for SMS today.
Well, emergency notifications are also distributed via SMS in my country, which may give SMS a kind of official status, but these are also broadcasted via other channels.
However, mainly due to the confirmation codes it&amp;rsquo;s really hard to ignore SMS, and most of the SMS messaging apps (on Android, at least) use a modern conversation view, as opposed to how older phones worked with SMS as per separate messages.
And this leads to a problem.&lt;/p&gt;
&lt;p&gt;The first one is that you can&amp;rsquo;t block SMS from non-contacts, because these security codes are likely to be sent from some corporate number.
While you could add such numbers to your contact lists, and be done with it, the problem arises when you want an SMS from a new service, so you basically have to disable filtering.
Which defeats the purpose.&lt;/p&gt;
&lt;p&gt;And the second problem is worse because the spam comes from the same phone numbers that are used to send you security codes.
My bank, for example, not only shows me ads when I use their official app but also occasionally sends me ads via SMS from the same number they use to confirm operations.
And they use the same number for spam calls too!
You basically have to accept this.
I call it &lt;em&gt;promoted spam&lt;/em&gt; because it uses the same communication channel it uses for important stuff, just so you couldn&amp;rsquo;t block it easily.&lt;/p&gt;
&lt;p&gt;Other companies, like clothing companies, for instance, have these club cards, that you register in order to have a discount from time to time or some other benefits.
Guess what, in order to register such a card you have to supply both your phone number and your e-mail.
And while e-mail is easy enough to ignore, they just keep spamming you with new ads even though the last time you&amp;rsquo;ve bought anything from them was 3 years ago.
For that matter, you can&amp;rsquo;t give them a fake phone number because of the confirmation code they sent you before applying for a discount.&lt;/p&gt;
&lt;p&gt;The most fun part is that my phone operator has a paid feature that blocks such SMS spam!
And they remind me of it every single time I get a spam message that they have an anti-spam feature I can subscribe to.
It&amp;rsquo;s like, they &lt;strong&gt;know&lt;/strong&gt; it&amp;rsquo;s a &lt;strong&gt;spam&lt;/strong&gt; SMS, they &lt;strong&gt;let it through&lt;/strong&gt;, and immediately after it reaches you, they &lt;strong&gt;send another spam SMS&lt;/strong&gt; that &lt;strong&gt;advertises&lt;/strong&gt; you an &lt;strong&gt;anti-spam feature&lt;/strong&gt;!
I&amp;rsquo;d rather change my operator than subscribe to something like that.&lt;/p&gt;
&lt;h2 id=&#34;just-unsubscribe&#34;&gt;Just unsubscribe&lt;/h2&gt;
&lt;p&gt;This is what I often hear when I brag about spam or read about it online.&lt;/p&gt;
&lt;p&gt;Well, first of all, not all spam is something I&amp;rsquo;ve willingly subscribed to.
Some of it is automated when you register a club card or some other account of sorts, and usually, there&amp;rsquo;s no way to disable these messages upon registration.&lt;/p&gt;
&lt;p&gt;Some services don&amp;rsquo;t even have a way to cancel subscriptions!
I once participated in a micro-controller-related conference, and in order to sign up, I used my personal e-mail, instead of the work one.
It was a giant mistake, motivated by the fact, that due to security reasons it was impossible to use work e-mail outside the office, and I thought that I may need my e-mail for confirmation or some paperwork when I&amp;rsquo;ll arrive.
Not only I didn&amp;rsquo;t need it, but I still receive yearly emails about upcoming conferences, highlights, and other stuff.
And there&amp;rsquo;s no way to unsubscribe.
I don&amp;rsquo;t have an account, their e-mail is random every time, they don&amp;rsquo;t respect GMail&amp;rsquo;s &amp;ldquo;unsubscribe me&amp;rdquo; feature, and there&amp;rsquo;s no e-mail to write back to a real human to take me off the mailing list.
I&amp;rsquo;ve made a custom rule that deletes messages from them automatically, but it still manages to come through somehow sometimes.&lt;/p&gt;
&lt;p&gt;And I&amp;rsquo;m not even talking about malicious spam, which is a different kind of beast at all.
You can&amp;rsquo;t unsubscribe from it, obviously.
Otherwise, it wouldn&amp;rsquo;t be as effective as it is.&lt;/p&gt;
&lt;p&gt;But as I&amp;rsquo;ve said - e-mail is easy enough to automate and ignore, but SMS isn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Much like the situation with the conference, you can&amp;rsquo;t unsubscribe from most promoted SMS spam.
Companies just don&amp;rsquo;t even admit they&amp;rsquo;re sending anything to you like these messages don&amp;rsquo;t exist.
I&amp;rsquo;ve tried coming to a customer&amp;rsquo;s office and speaking with a manager about the issue, but they basically told me to give up, and accept the situation as is.
I&amp;rsquo;ve changed operator since then, but the story repeated.&lt;/p&gt;
&lt;p&gt;So, no.
You can&amp;rsquo;t unsubscribe from the majority of annoying spam.
It&amp;rsquo;s not a solution.
Forget it.&lt;/p&gt;
&lt;h2 id=&#34;just-ignore-it&#34;&gt;Just ignore it&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve used e-mail for a long time, and in the early days, I spent a lot of time marking stuff as spam, because filters weren&amp;rsquo;t that good enough yet, and spammers were creative.
But not all people spent time, analyzing what is a spam message and what isn&amp;rsquo;t.
And, more importantly, spammers are creative, and when we&amp;rsquo;re talking about malicious spam, which wants not only to advertise something you don&amp;rsquo;t want but also to steal your money or personal information, scammers today are as creative as they have ever been.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve linked a TED talk at the beginning of this rant, and there&amp;rsquo;s one example of spam, that I&amp;rsquo;m not getting too often, but still see in the spam folder from time to time.
But I know some people, who were victims of such emails, sending money to scammers.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s the problem.
Spam works, and spammers get what they want more often than you think.&lt;/p&gt;
&lt;p&gt;There are a lot of similarities between spam messages/calls and TV advertisements.
They steal your time and focus and promote you something you likely don&amp;rsquo;t even need.
And unfortunately, nothing can be done about it really.&lt;/p&gt;
&lt;p&gt;You can be extremely careful, and not put your e-mail and phone number anywhere, and while this cuts a lot, there are still systems that probe wide ranges of phone numbers automatically.
I&amp;rsquo;ve actually tried it several times, and still somehow managed to get spam, even though nobody knows about this e-mail address, and phone number.&lt;/p&gt;
&lt;p&gt;With SMS there&amp;rsquo;s also a point of trust because so much secure information comes through this communication channel, I&amp;rsquo;m a bit afraid to use anti-spam systems.
As they will likely send my SMS to their server, and we all know that user personal data leaks every week these days.&lt;/p&gt;
&lt;p&gt;So, yeah, unfortunately, spam is something I just had to accept, and I&amp;rsquo;m not sure if the situation will ever get better.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Spam Rant&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 26 Jul 2022 20:21:00 +0300</pubDate>
    </item><item>
      <title>Limiting Horizontal Scroll In Emacs</title>
      <link>https://andreyor.st/posts/2022-07-20-limiting-horizontal-scroll-in-emacs/</link>
      <guid>https://andreyor.st/posts/2022-07-20-limiting-horizontal-scroll-in-emacs/</guid>
      <description>&lt;p&gt;I use Emacs mainly for programming, but I also write a lot of non-code in it, either for this blog, documentation for my projects, or just when I take notes.
And I do it with a git-friendly style of formatting with a single sentence per line.
And because of that, I enable line truncation, to avoid wrapping text, because when the text is written this way, the wrapped version looks like a mess, in my opinion.
This also helps with code, that has long lines - the formatting is preserved and unexpected multi-line expressions don&amp;rsquo;t mess me up.&lt;/p&gt;
&lt;p&gt;But because lines get truncated when exceeding window width, it means that I have to use horizontal scrolling.
I rarely actually use scrolling, because this is a very good indication of a very long sentence, that should be rephrased into smaller ones, but still.
However, when I do have to scroll, there&amp;rsquo;s a problem - Emacs doesn&amp;rsquo;t limit horizontal scrolling properly.&lt;/p&gt;
&lt;p&gt;If you open some other editor, like Gedit, and disable line wrapping, you&amp;rsquo;ll see that the most amount of horizontal scrolling you can get is basically such that the last character of the longest line is at the right border of the window.
In Emacs, however, it&amp;rsquo;s not limited like that, and you can scroll past the last character of the longest line, and basically overshoot.
This can be handy when you want to have some empty space to the right, for comfortable writing, but I don&amp;rsquo;t need that.
Instead, I would like to get the behavior of editors like Gedit.&lt;/p&gt;
&lt;p&gt;Turns out, if you enable &lt;code&gt;horizontal-scroll-bar-mode&lt;/code&gt;, Emacs will show the scroll-bar at the bottom, which will not allow you to over-scroll text, like in Gedit.
But if you use a touchpad, or manually call &lt;code&gt;scroll-left&lt;/code&gt; it will continue scrolling.
So let&amp;rsquo;s fix this.&lt;/p&gt;
&lt;p&gt;The first thing we&amp;rsquo;ll need is a custom predicate, that will check if any line in the buffer exceeds buffer width.
There are some corner cases to be aware of, like if the buffer&amp;rsquo;s font size is changed via &lt;code&gt;text-scale-adjust&lt;/code&gt;, or if the line numbers are displayed, so this predicate should account for that too.
I wrote such predicate like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truncated-lines-p&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Non-nil if any line is longer than &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`window-width&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; + &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`window-hscroll&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Returns t if any line exceeds the right border of the window.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Used for stopping scroll from going beyond the longest line.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Based on &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`so-long-detected-long-line-p&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-excursion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;goto-char&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-min&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; This computes a more accurate width rather than `window-width&amp;#39;, and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; respects `text-scale-mode&amp;#39; font width.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;/&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-body-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-font-width&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hscroll-offset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; `window-hscroll&amp;#39; returns columns that are not affected by&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; `text-scale-mode&amp;#39;.  Because of that, we have to recompute the correct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; `window-hscroll&amp;#39; by multiplying it with a non-scaled value and&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; dividing it with a scaled width value, rounding it to the upper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; boundary.  Since there&amp;#39;s no way to get unscaled value, we have to get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; a width of a face that is not scaled by `text-scale-mode&amp;#39;, such as&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; `window-divider&amp;#39; face.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ceiling&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;/&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-hscroll&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-font-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;window-divider&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;float&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-font-width&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line-number-width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; Compensate for line number width.  Add support for&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; other modes if you use any, like `linum-mode&amp;#39;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bound-and-true-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;display-line-numbers-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;display-line-numbers-width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              0))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;threshold&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;window-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hscroll-offset&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;line-number-width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         -2))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; -2 to compensate rounding during calculation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;excessive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eobp&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;save-restriction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;narrow-to-region&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;min&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt; 1 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;threshold&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point-max&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;forward-line&lt;/span&gt; 1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;bolp&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;eobp&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;=&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;point&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;start&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;threshold&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;excessive&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;t&lt;/span&gt;))))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To illustrate what it does, here&amp;rsquo;s a screenshot of the Emacs window with this blog post, as I edit it:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-07-20-limiting-horizontal-scroll-in-emacs/lines_exceed_window_width.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve made the frame smaller and enabled the &lt;code&gt;horizontal-scroll-bar-mode&lt;/code&gt; to better show what I mean.
In the echo area &lt;code&gt;t&lt;/code&gt; is displayed because I&amp;rsquo;ve called &lt;code&gt;truncated-lines-p&lt;/code&gt;, and it shows that some line exceeds the width of the window.
You can see that lines go beyond the right border (though there&amp;rsquo;s no arrow in the fringe, as I disabled these), and if I scroll with the scroll-bar, Emacs stops scrolling at about this position:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-07-20-limiting-horizontal-scroll-in-emacs/line_end_reached.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Now &lt;code&gt;nil&lt;/code&gt; is displayed in the echo area because I&amp;rsquo;ve called &lt;code&gt;truncated-lines-p&lt;/code&gt; again, which means that the predicate works, since there&amp;rsquo;s no need to scroll anymore, all lines are not truncated by the right border.
However, I can continue scrolling if I use the touchpad:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-07-20-limiting-horizontal-scroll-in-emacs/overscroll.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Note, that the handle in the scroll bar changed its width.
Emacs calculates the width of the handle based on the longest line currently visible in the window, meaning that it will change depending on the position in the buffer.
And perhaps scroll-bar width limited for what you&amp;rsquo;re seeing is a performance optimization.
My function does it for the whole buffer, and there is a lot of code for calculating text width with respect to the horizontal scroll.
Thus, the calculation process may not seem very optimal, but benchmarking this function seems to have decent performance on my &lt;code&gt;1603&lt;/code&gt; lines &lt;code&gt;init.el&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; some lines exceed the width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;benchmark&lt;/span&gt; 1000 &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truncated-lines-p&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; Elapsed time: 0.597171s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; no lines exceed the width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;benchmark&lt;/span&gt; 1000 &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truncated-lines-p&lt;/span&gt;)) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; Elapsed time: 1.247346s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In practice, I never feel any slowdown from it.
The only thing left is to make &lt;code&gt;sroll-left&lt;/code&gt; to actually use it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;scroll-left&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:before-while&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;prevent-overscroll&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truncate-lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;major-mode&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vterm-mode&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;term-mode&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;truncated-lines-p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I use a &lt;code&gt;before-while&lt;/code&gt; advice, which acts like a predicate on its own and doesn&amp;rsquo;t run function if the result is &lt;code&gt;nil&lt;/code&gt;.
As can be seen, it does an additional check for &lt;code&gt;truncate-lines&lt;/code&gt; to be on, since if lines are not truncated there&amp;rsquo;s no reason to ever scroll left.
I also would like to prevent this from working in certain major modes, like terminals, since these automatically wrap lines themselves.&lt;/p&gt;
&lt;p&gt;Hope this is useful for someone, and if anybody knows a more robust way to calculate text width with the respect to the zoom level feel free to suggest improvements.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Limiting Horizontal Scroll In Emacs&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 20 Jul 2022 00:00:00 +0000</pubDate>
    </item><item>
      <title>Project.el enhancements</title>
      <link>https://andreyor.st/posts/2022-07-16-project-el-enhancements/</link>
      <guid>https://andreyor.st/posts/2022-07-16-project-el-enhancements/</guid>
      <description>&lt;p&gt;After publishing the last post I thought why won&amp;rsquo;t I post such things here occasionally?
I have a few pieces of Emacs Lisp in my configuration that I wrote for myself some time ago to fix some annoyances or improve a certain workflow.
Previously I&amp;rsquo;ve used a literate approach for my Emacs configuration which listed all these notes, but it was tedious to maintain, so I&amp;rsquo;ve opted out for a simpler &lt;code&gt;init.el&lt;/code&gt;.
But I still would like to share some pieces in a more elaborated form.
Moreover, I&amp;rsquo;ve already &lt;a href=&#34;https://andreyor.st/posts/2020-05-01-dynamic-title-for-treemacs-workspace/&#34;&gt;done&lt;/a&gt; &lt;a href=&#34;https://andreyor.st/posts/2020-05-07-making-emacs-tabs-work-like-in-atom/&#34;&gt;it&lt;/a&gt; &lt;a href=&#34;https://andreyor.st/posts/2020-05-10-making-emacs-tabs-look-like-in-atom/&#34;&gt;before&lt;/a&gt;, and now, since I don&amp;rsquo;t use these packages, it&amp;rsquo;s easier to find these in a more organized place, than search in the commit history.&lt;/p&gt;
&lt;p&gt;One such thing that I&amp;rsquo;d like to share is a configuration of the inbuilt &lt;code&gt;project.el&lt;/code&gt;, which makes it a bit more pleasant to work with.&lt;/p&gt;
&lt;h2 id=&#34;finding-project-root-based-on-specific-root-markers&#34;&gt;Finding project root based on specific root-markers&lt;/h2&gt;
&lt;p&gt;Long ago I added a function that searches for a project root a bit differently from how &lt;code&gt;project.el&lt;/code&gt; does it by default.
It does so by searching for specific files, that I&amp;rsquo;ve specified like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root-markers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;#39;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Cargo.toml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;compile_commands.json&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;compile_flags.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;project.clj&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;.git&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;deps.edn&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;shadow-cljs.edn&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Files or directories that indicate the root of a project.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &amp;#39;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;repeat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;project&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may wonder why I&amp;rsquo;ve included &lt;code&gt;.git&lt;/code&gt; as a project marker, but I often work with submodules, and I want such submodules to be treated as separate projects.
The default &lt;code&gt;project-try-vc&lt;/code&gt; treats submodules as part of a bigger project, which is logical, I guess, but I want it to act a bit differently.
And since not all of my submodules have one of the specified markers, it&amp;rsquo;s easy to search for the git directory and be done with it.&lt;/p&gt;
&lt;p&gt;Next, we need a function that checks if a given path has any of these markers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Check if the current PATH has any of the project root markers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;found&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dolist&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;marker&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root-markers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-exists-p&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;marker&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;found&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;marker&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing fancy, just a linear search for any of the markers under the current directory.
The search terminates as soon as one of the files is found.&lt;/p&gt;
&lt;p&gt;The main piece here is the &lt;code&gt;project-find-root&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-find-root&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Search up the PATH for &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`project-root-markers&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;found&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;equal&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root-p&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;file-name-directory&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;directory-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;found&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;transient&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-to-list&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;project-find-functions&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-find-root&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As can be seen, this function is added to the list of &lt;code&gt;project-find-functions&lt;/code&gt;, and all it does is simply look for a marker file in the current directory, and if it is not found it goes up the directory.
If file is found, it returns a &lt;code&gt;(transient . &amp;quot;path/to/root&amp;quot;)&lt;/code&gt; that &lt;code&gt;project.el&lt;/code&gt; expects.
In practice, with this function early enough in the list, &lt;code&gt;project-try-vc&lt;/code&gt; is never called, and I get very predictable project roots.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;A suggestion came from another Emacs user, that there&amp;rsquo;s a function that can search up from the current directory, called &lt;code&gt;locate-dominating-file&lt;/code&gt;.
It accepts a path as its first argument, and a file to search for as a second argument.
It may not seem useful in this use case, since we need to search for multiple files, but instead of a file, this function also can accept a predicate, that will tell if a given file exists.
Thus, the &lt;code&gt;project-find-root&lt;/code&gt; function can be rewritten as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-find-root&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Search up the PATH for &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`project-root-markers&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-let&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;locate-dominating-file&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-root-p&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cons&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;transient&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;root&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is why I love Emacs!
It has a lot of functions ready to be used, and a passionate community, that suggests improvements and makes the experience even better.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;saving-only-project-buffers-before-compilation&#34;&gt;Saving only project buffers before compilation&lt;/h2&gt;
&lt;p&gt;I often use project&amp;rsquo;s commands, defined under the &lt;code&gt;project-prefix-map&lt;/code&gt;.
One of these is &lt;code&gt;project-compile&lt;/code&gt;, which I use for all sorts of things, from running tests to deploying.
However, it has an annoying habit to ask whether I want to save some buffers before I run any command.
Why yes, I want to save some buffers, but only if they belong to the current project!
So let&amp;rsquo;s fix this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-save-some-buffers&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Save some modified file-visiting buffers in the current project.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;Optional argument ARG (interactively, prefix argument) non-nil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;means save all with no questions.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;interactive&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-current&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pred&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall-interactively&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;save-some-buffers&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arg&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pred&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just a simple function that obtains the current project, queries all project buffers, and creates a custom predicate for the &lt;code&gt;save-some-buffers&lt;/code&gt; function.
I&amp;rsquo;m not sure why &lt;code&gt;project.el&lt;/code&gt; doesn&amp;rsquo;t do it by itself, but we can always advise things:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-compile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;save-project-buffers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Only ask to save project-related buffers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-current&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-save-buffers-predicate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This fixes only half of the problem, however.&lt;/p&gt;
&lt;p&gt;Imagine, you&amp;rsquo;re running tests by calling &lt;code&gt;project-compile&lt;/code&gt; and one of the tests fails.
You look in the &lt;code&gt;*compilation*&lt;/code&gt; buffer why it failed and fix it.
Then you go to the &lt;code&gt;*compilation*&lt;/code&gt; buffer once again and hit the &lt;kbd&gt;g&lt;/kbd&gt; key to re-run tests.
But instead of running tests, you&amp;rsquo;re being asked if you want to save some buffers, even though you&amp;rsquo;ve saved all buffers in the project beforehand.
Turns out, that &lt;kbd&gt;g&lt;/kbd&gt; simply calls the &lt;code&gt;recompile&lt;/code&gt; function, which knows nothing about the project, and will prompt you to save buffers, that aren&amp;rsquo;t in the project and are unsaved.
This, once again, can be fixed with a piece of advice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recompile&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:around&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;optional&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;edit-command&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;save-project-buffers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Only ask to save project-related buffers if inside a project.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-current&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-current&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;compilation-save-buffers-predicate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;lambda&lt;/span&gt; () (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;memq&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;current-buffer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;project-buffers&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;edit-command&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;funcall&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;edit-command&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We simply check if current &lt;code&gt;*compilation*&lt;/code&gt; buffer is a part of a project, since and do the same trick, setting &lt;code&gt;compilation-save-buffers-predicate&lt;/code&gt; to our custom predicate that is aware of the project.
This, however, works best when you customize the &lt;code&gt;project-compilation-buffer-name-function&lt;/code&gt; to use &lt;code&gt;project-prefixed-buffer-name&lt;/code&gt;, so you can compile multiple projects, and it won&amp;rsquo;t be confusing when to save what buffers.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Project.el enhancements&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 16 Jul 2022 12:37:00 +0300</pubDate>
    </item><item>
      <title>Automatic refreshing of package archives for Emacs</title>
      <link>https://andreyor.st/posts/2022-07-15-refresh-package-contents-automatically/</link>
      <guid>https://andreyor.st/posts/2022-07-15-refresh-package-contents-automatically/</guid>
      <description>&lt;p&gt;I was going through my git commit history in my public &lt;a href=&#34;https://github.com/andreyorst/dotfiles&#34; target=&#34;_blank&#34;&gt;dotfiles repository&lt;/a&gt; and noticed that prior to using &lt;a href=&#34;https://github.com/radian-software/straight.el&#34; target=&#34;_blank&#34;&gt;straight.el&lt;/a&gt; I&amp;rsquo;ve, like many, used an inbuilt solution for managing packages, called &lt;code&gt;package.el&lt;/code&gt;.
However, there was one thing that bothered me, and one of the reasons that made me think about switching to &lt;code&gt;straight&lt;/code&gt; was the fact, that a lot of times when I wanted to update or install packages, I couldn&amp;rsquo;t, due to an outdated package cache.
So I&amp;rsquo;ve fixed this, but since I&amp;rsquo;ve moved to straight I no longer needed this piece of code, and hence I&amp;rsquo;ve deleted it.
But it might be useful for people who use &lt;code&gt;package.el&lt;/code&gt;, so I&amp;rsquo;ve decided to share it here.&lt;/p&gt;
&lt;p&gt;The first thing needed is a custom variable to store the last refresh date.
I&amp;rsquo;ve chosen Custom because it is persisted on disk, which allows me to use &lt;code&gt;customize-save-variable&lt;/code&gt; later to make the value persist across sessions, and be easily reset via the customization interface:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-last-refresh-date&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Date and time when package lists have been refreshed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  This variable is then used to check whether
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`package-refresh-contents&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; call is needed before calling
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`package-install&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;. The value of this variable is updated when
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`package-refresh-contents&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; is called.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  See &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`package-refresh-hour-threshold&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; for the amount of time needed to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  trigger a refresh.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;package&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This variable is useful on its own, but we also need another one, that will specify how much time needs to pass since the last refresh to trigger package refreshing again.
I&amp;rsquo;ve chosen to store a number of hours since you don&amp;rsquo;t need to refresh package contents really often, but it may be a personal preference.
For example, if you update or install packages once a week, it doesn&amp;rsquo;t really matter, but if you, like me often tried cool packages that people share over the internet, the refresh rate may be set a bit lower than that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defcustom&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-automatic-refresh-threshold&lt;/span&gt; 24
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Amount of hours since last &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`package-refresh-contents&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt; call
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;  needed to trigger automatic refresh before calling &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;`package-install&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:type&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;package&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With these two helper variables we can start &amp;ldquo;patching&amp;rdquo; &lt;code&gt;package.el&lt;/code&gt; so it would use it.
We don&amp;rsquo;t need to modify code, thanks to the advanced advice system:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-install&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:before&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-refresh-contents-maybe&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-last-refresh-date&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;/&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;float-time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;time-subtract&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date-to-time&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%Y-%m-%dT%H:%M&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;date-to-time&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-last-refresh-date&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  3600)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-automatic-refresh-threshold&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-refresh-contents&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;define-advice&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;package-refresh-contents&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;amp;rest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;update-package-refresh-date&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;customize-save-variable&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;package-last-refresh-date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;format-time-string&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%Y-%m-%dT%H:%M&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first advice ensures that before installing a package we&amp;rsquo;ll refresh package contents if enough time has passed since the last refresh, that is.
The second one simply updates the last refresh time, and stores it in the custom file, which I, personally, changed to &lt;code&gt;custom.el&lt;/code&gt; in my Emacs directory, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cus-edit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:custom&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;custom-file&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;expand-file-name&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;custom.el&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;user-emacs-directory&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:init&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;load&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;custom-file&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;:noerror&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file is not a part of my version control system and hosts a lot of machine local configuration, so it was natural to store the last refresh date in it too.
Of course, it is possible to store it in an arbitrary file, since it&amp;rsquo;s just a string, and read it inside the &lt;code&gt;package-install&lt;/code&gt; advice, but customize makes it seamless, and worked for me quite well.&lt;/p&gt;
&lt;p&gt;Hope this was a useful tip!&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Automatic refreshing of package archives for Emacs&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 15 Jul 2022 09:27:00 +0300</pubDate>
    </item><item>
      <title>Fennel Game Jam 2022</title>
      <link>https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/</link>
      <guid>https://andreyor.st/posts/2022-06-12-fennel-game-jam-2022/</guid>
      <description>&lt;p&gt;Quite recently a Fennel game jam happened on &lt;a href=&#34;https://itch.io/&#34; target=&#34;_blank&#34;&gt;itch.io&lt;/a&gt; and I&amp;rsquo;ve decided to participate.
I&amp;rsquo;ve been part of the Fennel community for some years, and every once in a while a lot of people from this community participated in a lisp game jam, but I&amp;rsquo;ve never made a game before, so I&amp;rsquo;ve skipped these events.
However, when the Fennel-specific game jam was announced I decided that I must finally put myself together and participate.&lt;/p&gt;
&lt;p&gt;The rules of the jam were quite relaxed - you basically had to use fennel for game programming, and release the game under an &lt;a href=&#34;https://opensource.org/licenses&#34; target=&#34;_blank&#34;&gt;OSI approved license&lt;/a&gt;.
No theme, no engine restrictions, no size requirement - an ideal situation for a programmer like me, who doesn&amp;rsquo;t know how to make a game, at all.
When I was young, and I mean, like almost 20 years ago, I only toyed with &lt;a href=&#34;https://en.wikipedia.org/wiki/Adobe_Flash#Macromedia&#34; target=&#34;_blank&#34;&gt;Macromedia Flash&lt;/a&gt; and ActionScript 2.0 at my school computer class, making interactive cartoons, which can hardly be considered games.
It&amp;rsquo;s not like I&amp;rsquo;m a complete stranger to game programming though, we had a very brief introduction to game programming at the university, except we never actually programmed games during these courses.
So, for example, I know what delta time is, how it should be used, or how to do vector math needed for basic movement, but this doesn&amp;rsquo;t count as experience.
If you read my blog, you may remember my small projects like &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/&#34;&gt;raycasting&lt;/a&gt; and &lt;a href=&#34;https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/&#34;&gt;raymarching&lt;/a&gt;, which feature movement, camera programming, basic collision detection, and a basic game-loop.
So actually I felt prepared when I decided to enter the jam.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve already tried LÖVE2D in the mentioned raymarching example, so I&amp;rsquo;ve decided to change things up a bit since I&amp;rsquo;ve wanted to explore another project - &lt;a href=&#34;https://tic80.com/&#34; target=&#34;_blank&#34;&gt;TIC-80&lt;/a&gt;.
The change from LÖVE2D to TIC-80 actually made it easier for me, since I could do the sprite-work and sound effects inside tic&amp;rsquo;s inbuilt editors.
So I&amp;rsquo;ve begun to work on it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll try to structure this post as a series of days based on the notes I made during the event.
There probably will not be any code though, as I have no early versions, since I&amp;rsquo;ve opted out of using version control systems for this project, to keep the retro vibe of the fantasy computer.&lt;/p&gt;
&lt;h2 id=&#34;day-1&#34;&gt;Day 1&lt;/h2&gt;
&lt;p&gt;The hardest day in my opinion because it is the day when I &lt;strong&gt;have&lt;/strong&gt; to start working on a project I haven&amp;rsquo;t had any thoughts about beforehand.
I&amp;rsquo;ve sat down and thought about what kind of game I &lt;em&gt;can&lt;/em&gt; make in the limited time of the event which was going from May 25 to Jun 1st.
Given 5 days and almost no game development experience, I&amp;rsquo;ve decided to play it safe and make a Breakout-like game.
Though a plain breakout clone would be a bit boring, so I&amp;rsquo;ve decided that I&amp;rsquo;ll put a small twist once you destroy the final block which would shake things a bit and hopefully be a welcome surprise.&lt;/p&gt;
&lt;p&gt;Now, since the theme was chosen I at least knew what I needed to start - a ball, a platform, and a box to bounce the ball to prevent it from flying away to infinity.
But I didn&amp;rsquo;t know how to do anything in tic, so I&amp;rsquo;ve opened up a &lt;a href=&#34;https://tic80.com/learn&#34; target=&#34;_blank&#34;&gt;manual&lt;/a&gt;.
The manual is minimalist, to say the least, and doesn&amp;rsquo;t provide a lot of info beyond essential things.
So I&amp;rsquo;ve picked up the &lt;code&gt;circ&lt;/code&gt; &lt;code&gt;rect&lt;/code&gt; and &lt;code&gt;rectb&lt;/code&gt; functions and started working.
This was my first result:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day1.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This has very basic hard-coded physics, meaning that I&amp;rsquo;ve literally defined a vector of all ball velocities and just cycled through it when the ball collided with any world object.
But it already has some interesting stuff done, which I haven&amp;rsquo;t changed much afterward.&lt;/p&gt;
&lt;p&gt;The first thing is that It has a proper world to screen coordinate transformation, which I&amp;rsquo;ve kinda never done before.
It&amp;rsquo;s a simple thing, I just have a world X and Y offsets that made the game world, e.g. the box rest, not in the top left corner but 10 pixels to the right and down.
All game physics was calculated with the top left corner in &lt;code&gt;0,0&lt;/code&gt; and then translated before drawing.&lt;/p&gt;
&lt;p&gt;The platform tracks its position and makes sure not to go outside the world boundaries.
And the ball is checked for collisions with everything but the lower boundary.
There, instead of a collision a basic &lt;code&gt;game-over?&lt;/code&gt; flag is set to interrupt the game loop.&lt;/p&gt;
&lt;p&gt;I was pretty satisfied for day one, especially since it wasn&amp;rsquo;t really a full day of me programming this, but only 3 hours after work.
The jam started at 10:00 AM in my time zone, and my work day also starts at the same time, so I had to begin working on a game 9 hours after the start of the jam.
I&amp;rsquo;m sure this is a common situation for most other participants, though perhaps they have had time before work too.&lt;/p&gt;
&lt;h2 id=&#34;day-2&#34;&gt;Day 2&lt;/h2&gt;
&lt;p&gt;I knew that I&amp;rsquo;ll not be able to move forward with the current physics system I&amp;rsquo;ve added to the game, so I spent most of the second day fighting with the collision system.
This was the result I got:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day2.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This had really wonky surface normal calculations, and you can see that the ball isn&amp;rsquo;t particularly happy with the results, as it just decides to leave the game.
I wasn&amp;rsquo;t happy with it either, but it was a move in the right direction.&lt;/p&gt;
&lt;p&gt;In addition to &lt;em&gt;improved&lt;/em&gt; physics, I&amp;rsquo;ve added destructible bricks with a random amount of health represented by a color.
The color was an accident, as I used brick health in place of the brick color when bricks were drawn on the screen, but I actually liked it.
The health was distributed randomly, but I&amp;rsquo;ve been focused on physics, so I&amp;rsquo;ve left it as is.&lt;/p&gt;
&lt;p&gt;There were two main problems.
First, I&amp;rsquo;ve re-used some linear algebra code from my raymarching project, mainly the calculation of the distance to the box and the calculation of the normal.
However, the calculation of a normal was done for a 3D world and wasn&amp;rsquo;t as meaningful for 2D space.
I&amp;rsquo;m not sure whether I&amp;rsquo;ll be able to explain the general method, but the idea is that I&amp;rsquo;ve found an intersection point, and picked two more points one below the surface and to the left and another above the surface and to the right.
Then I used some vector math to find a normal based on distance estimation from these points to the intersection point.
This works quite well for 3D, given that all reflections in the raymarching demo were correct, but in 2D it resulted in weird unexpected reflections (not in the video).&lt;/p&gt;
&lt;p&gt;Unfortunately, I have this kind of problem that once I&amp;rsquo;ve fixated on some solution I can&amp;rsquo;t see another one until I step away from the problem for a bit.
So I&amp;rsquo;ve kept the current physics and ended the day 2 session.&lt;/p&gt;
&lt;h2 id=&#34;day-3&#34;&gt;Day 3&lt;/h2&gt;
&lt;p&gt;This day was mostly spent polishing and rewriting the collision system.
I&amp;rsquo;ve almost fully fixed bugs with unexpected angles, but the ball still managed to find its way inside the platform.
I couldn&amp;rsquo;t spend too much time on it, so I&amp;rsquo;ve decided to leave it as is, and maybe fix it after everything else is done.&lt;/p&gt;
&lt;p&gt;In addition to that, I&amp;rsquo;ve made it such that the block health depends on the row it was spawned at.
So the lower blocks had 1 health, the next row above it had 2 health, and so on.
This can be seen with this nice color transition from purple to orange.&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day3.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also done some basic point systems that added 100 points when you destroy a brick, and 10 points upon collision.
There are now lives, so you can lose the ball several times before the &amp;ldquo;game over&amp;rdquo;.
Satisfied with that I&amp;rsquo;ve ended the third day, realizing that theirs not that much time left, but also not too far til the game will be complete.&lt;/p&gt;
&lt;p&gt;For the next two days, I was planning to add graphics and a small twist that will hopefully make the game a bit more interesting.&lt;/p&gt;
&lt;h2 id=&#34;day-4&#34;&gt;Day 4&lt;/h2&gt;
&lt;p&gt;Up until this day I&amp;rsquo;ve drawn everything with basic rectangles and this wasn&amp;rsquo;t going to cut for the jam in my opinion.
So for the fourth day, I&amp;rsquo;ve decided to focus on some graphics and sounds.&lt;/p&gt;
&lt;p&gt;The inbuilt sprite editor is quite good, actually.
I&amp;rsquo;ve only tried the &lt;a href=&#34;https://github.com/LibreSprite/LibreSprite&#34; target=&#34;_blank&#34;&gt;LibreSprite&lt;/a&gt;, an open-source fork of aseprite sprite editor, and it was a bit sluggish, perhaps because it was using a software cursor, which felt unresponsive.
But with TIC&amp;rsquo;s sprite editor it wasn&amp;rsquo;t a problem and I quickly drew basic sprites for bricks, the platform, and the ball:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/sprites.gif&#34;
         alt=&#34;Figure 1: Sprites&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Sprites&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Then I decided to add power-ups.&lt;/p&gt;
&lt;p&gt;There are three classic power-ups that affect the size of the ball or the platform - the big ball, the long platform, and the short platform.
All these powers are timer-based, with a small exception for the big ball - if you lose the ball while it&amp;rsquo;s big, the power-up is also lost.
In addition to that, there are two speed-related power-ups, one that increases the ball&amp;rsquo;s speed, and one that decreases it.&lt;/p&gt;
&lt;p&gt;Speaking of speed, I&amp;rsquo;ve also made it so that the speed of the ball gradually grows during the game up to twice the initial speed.
And there&amp;rsquo;s a mentioned power-up to increase and decrease the value by a quarter.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demonstration of various power-ups:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day4.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;As can be seen, the ball still can act weirdly, almost spinning around the platform, but I&amp;rsquo;ve already spent most of my time on graphics and sounds, so I&amp;rsquo;ve decided to left it for the last day.&lt;/p&gt;
&lt;h2 id=&#34;day-5&#34;&gt;Day 5&lt;/h2&gt;
&lt;p&gt;The last day of the jam!
I&amp;rsquo;ve added more graphics, as I wasn&amp;rsquo;t able to figure out how to measure things in seconds, as the values of the &lt;code&gt;time&lt;/code&gt; function were kinda &lt;em&gt;weird&lt;/em&gt;.
So I&amp;rsquo;ve opted out of colored bars that gradually decrease in length.
I&amp;rsquo;ve also decided to add some effects, like screen shake when the ball is big.
Here&amp;rsquo;s how it looks:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/day5.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;At this point, I&amp;rsquo;ve started working on the &lt;em&gt;twist&lt;/em&gt; and polishing things out.
For the twist I&amp;rsquo;ve decided to do a boss battle at the end of the game, essentially turning the Breakout game into Pong when the last brick is destroyed:&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted&gt;&lt;source src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/boss-battle.mp4&#34; type=&#34;video/mp4&#34;&gt;
Your browser does not support the video tag.&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The boss has a fixed amount of health, and each hit with the ball removes some amount of it.
If the big ball power-up is active the ball deals twice the damage.
I&amp;rsquo;ve actually made it that this damage multiplier also affects bricks, so bricks are destroyed a bit faster now too.
And if you score the boss, it&amp;rsquo;ll lose 5 times hp of a single hit, although it&amp;rsquo;s almost impossible, unless you picked a lot of speed power-ups.&lt;/p&gt;
&lt;p&gt;Boss&amp;rsquo; health is represented with another bar that changes color depending on the health range, going from green at full to red near the end.
To win the game you must defeat the boss, which is actually a bit tricky and I can&amp;rsquo;t do it consistently myself either.
Speaking of power-ups, there&amp;rsquo;s a random chance to spawn a power-up in a random location during the boss battle.
The chance of spawning is very low though.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve uploaded the game to itch as a web build, and noticed a weird problem.
All power-ups were wearing off too fast!
I couldn&amp;rsquo;t understand what the problem is, because to my knowledge I did a proper way of handling power-up times - I obtained the current game-time with the call to the &lt;code&gt;time&lt;/code&gt; function, added a fixed amount to it, and checked on each frame if the value returned by &lt;code&gt;time&lt;/code&gt; surpassed it.
To simplify, upon activation of a timer based power-up, I did this &lt;code&gt;end = time() + powerup_duration&lt;/code&gt;, and checked for &lt;code&gt;end &amp;lt; time()&lt;/code&gt; to disable the power-up.
Given that it is based on &lt;code&gt;time&lt;/code&gt; and not on some ticking mechanism, I&amp;rsquo;ve thought that it should work equally well regardless of frames per second.
Even more weird was that the ball speed was the same as on the desktop.
So in short - power-ups ended a lot faster, yet the rest of the speed was the same.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve decided to do it &amp;ldquo;properly&amp;rdquo; and calculated the delta time.
Then I multiplied ball movement by newly calculated &lt;code&gt;dt&lt;/code&gt; and reworked power-ups to work based on ticks, meaning they weren&amp;rsquo;t tied to &lt;code&gt;time&lt;/code&gt; directly.
Checked that all works well on my desktop I&amp;rsquo;ve made a fresh web build, uploaded it to itch, and it was way too fast!
The ball speed now was superfast, power-ups ended almost immediately.
After a ton of debugging, and trying to make any sense out of the phrase that the main &lt;code&gt;TIC&lt;/code&gt; function is called 60 times per second, when it &lt;em&gt;clearly&lt;/em&gt; wasn&amp;rsquo;t, as the game speed was different between the web and Linux builds.
Then I made a Windows build, and it worked with the same speed as the web build, and I thought that maybe it was a bug in the Linux build.
I&amp;rsquo;ve checked what value of &lt;code&gt;dt&lt;/code&gt; was calculated on each platform, and the Linux build had a 10-fold difference from other platforms:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-06-12-fennel-game-jam-2022/tic-bug.png&#34;
         alt=&#34;Figure 2: Delta time differences between platforms&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Delta time differences between platforms&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The Linux build had a delta time value of approximately &lt;code&gt;0.001&lt;/code&gt; while the web and Windows build had &lt;code&gt;0.02&lt;/code&gt;.
I&amp;rsquo;ve tried an older version of TIC, and it had no such issue but didn&amp;rsquo;t support the Fennel version I was using for the game.
So I had to distribute the game only as a web build until the &lt;a href=&#34;https://github.com/nesbox/TIC-80/issues/1904&#34; target=&#34;_blank&#34;&gt;issue&lt;/a&gt; is fixed.
I&amp;rsquo;ve tweaked the speed by adding a &lt;code&gt;game_speed&lt;/code&gt; parameter that I could tweak around inside the web build to make the speed feel right.
After that, I pushed a final web build with these tweaks and submitted the game.&lt;/p&gt;
&lt;h2 id=&#34;jam-results&#34;&gt;Jam results&lt;/h2&gt;
&lt;p&gt;Because of my time zone, I was the first who submitted a game, but I couldn&amp;rsquo;t do any more work because the last hours of the jam were at nighttime here.
Out of 21 participants, only seven games were submitted, which actually a pretty great result, in my opinion, it&amp;rsquo;s a solid third!
Funnily enough, we have about 60 people in our &lt;code&gt;#fennel&lt;/code&gt; IRC channel on &lt;a href=&#34;https://libera.chat/&#34; target=&#34;_blank&#34;&gt;Libera.Chat&lt;/a&gt;, so 21 people is a third too.
The results can be viewed &lt;a href=&#34;https://itch.io/jam/fennel-game-jam-1/results&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;, and I suggest you try all games, as there are pretty cool entries!&lt;/p&gt;
&lt;p&gt;I managed to score third place, which actually surprised me a bit, given how simple the concept of my game was.
But I&amp;rsquo;m glad, and I think it&amp;rsquo;s a solid result for the first game.&lt;/p&gt;
&lt;p&gt;In retrospect, I think I could do some things better, especially in the user interface department.
Adding a proper menu, maybe an intro, making the interface look more like an arcade cabinet, which I&amp;rsquo;ve originally attempted, but my pixel-art skills are not that great yet.
But I still like the result, I feel that for a first game it turned out pretty great.
And the process was quite fun, which is the most important thing for me.&lt;/p&gt;
&lt;p&gt;I hope I&amp;rsquo;ll participate in more lisp-themed jams, maybe in a lisp game jam or the next Fennel jam.
I&amp;rsquo;ve always wanted to make games, and I had some ideas about the game I want to make in the Metroidvania genre.
Game jams are perfect for experiments, and you can learn a lot by doing things you never did before.
I&amp;rsquo;m not going to make a whole game during the jam as I want it to be a more complete thing, but the jam can help me to flesh out some main mechanics, be it the movement, or world-building practice.
So I&amp;rsquo;m looking forward to the upcoming events!&lt;/p&gt;
&lt;p&gt;This was a lot of fun, and I hope more people will join next time!
Thanks to everyone who participated, &lt;a href=&#34;https://www.mattroelle.com/&#34; target=&#34;_blank&#34;&gt;Matt Roelle&lt;/a&gt; for organizing the Jam, and everyone involved in Fennel and TIC-80 development.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Fennel Game Jam 2022&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 12 Jun 2022 12:37:00 +0300</pubDate>
    </item><item>
      <title>Wave Function Collapse Algorithm in ClojureScript</title>
      <link>https://andreyor.st/posts/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/</link>
      <guid>https://andreyor.st/posts/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/</guid>
      <description>&lt;p&gt;The last time I touched ClojureScript was &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/&#34;&gt;almost two years ago&lt;/a&gt;.
It was a really fun experience, and actually, it was a bit special to me personally.
Prior to that post, I only learned lisp&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; via books and mostly used it only for configuring Emacs, and while I&amp;rsquo;ve liked the idea of code as data and other lisp aspects, I never did anything more with the language.
So this was the first thing that I&amp;rsquo;ve done in lisp from start to finish, the first thing done in Clojure, the first interactive thing with some sort of visualizations.
And this is pretty much the reason I fell in love with Clojure and not with another dialect - I&amp;rsquo;ve used it for something &lt;em&gt;real&lt;/em&gt;, not just an exercise for the book, and I liked the syntax, the data structures, immutability, laziness, and other features.
Since that post I&amp;rsquo;ve got a job in Clojure, so now it&amp;rsquo;s my primary programming language and I love it still.
However, I have a lot less experience with ClojureScript, mainly because I mostly do backend development, and we have a separate team working on the frontend part.&lt;/p&gt;
&lt;p&gt;I like games, but I&amp;rsquo;ve never actually done anything more than simple demos of various game algorithms and techniques&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.
And I mostly did it in Fennel, because it&amp;rsquo;s also a very nice lisp-like language with a very similar syntax to Clojure.
I wanted to do more, but I wanted these experiments to be a bit more reachable, and possibly viewed directly in my blog, as it was with the raycasting example.
So I knew that I wanted to do something with ClojureScript instead of Fennel, which became my main language for this type of thing.
Another reason is that I&amp;rsquo;m thinking about doing some frontend programming in ClojureScript in the upcoming years.&lt;/p&gt;
&lt;p&gt;Luckily for me, not so long ago I found a really neat algorithm for generating worlds.
The algorithm is called Wave Function Collapse, and it actually has nothing to do with quantum physics.
In this post, I&amp;rsquo;ll try to walk you thru the algorithm, and explain how I&amp;rsquo;ve approached this problem.&lt;/p&gt;
&lt;h2 id=&#34;the-algorithm&#34;&gt;The algorithm&lt;/h2&gt;
&lt;p&gt;What makes this algorithm different from most procedural generation algorithms I&amp;rsquo;ve read about is that it is &lt;em&gt;extremely simple&lt;/em&gt;.
It can generate images based on a small sample of data, as shown below:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/coast.png&#34;
         alt=&#34;Figure 1: Example Input&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;Example Input&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/result.png&#34;
         alt=&#34;Figure 2: Generation result&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 2: &lt;/span&gt;Generation result&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;However, just implementing the algorithm from some description isn&amp;rsquo;t fun.
What I like to do, and this is a general approach I use for all my projects, is to get some assumptions about the thing I want to implement, and then do everything based on these assumptions only&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;.
So instead of learning how the algorithm is implemented, I&amp;rsquo;ve just observed its behavior with simple input.&lt;/p&gt;
&lt;p&gt;For example, let&amp;rsquo;s look again at the input sample, but let&amp;rsquo;s split it into tiles with a grid:&lt;/p&gt;
&lt;p&gt;&lt;a id=&#34;figure--example&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/example.png&#34;
         alt=&#34;Figure 3: Sample&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 3: &lt;/span&gt;Sample&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This sample specifies that for each tile on this image there are only so many possible neighbors.
For example, this tile in the middle can only have one unique neighbor on each of its sides:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/neighbors.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Other tiles may have two or more unique neighbors, and the job of the algorithm is to analyze each tile on the image, and track what neighboring cells it has, storing it into a ruleset.
And an image is then generated based on these adjacency rules only.&lt;/p&gt;
&lt;p&gt;This is basically what I knew about the algorithm when I started implementing it.
Of course, it&amp;rsquo;s not &lt;em&gt;that&lt;/em&gt; simple, but it&amp;rsquo;s still easy to grasp, and some nuances become apparent when you actually start working on it.
I&amp;rsquo;ll give the algorithm a more comprehensive explanation a bit later, as we&amp;rsquo;ll encounter problems.&lt;/p&gt;
&lt;h2 id=&#34;text-version-of-the-algorithm&#34;&gt;Text version of the algorithm&lt;/h2&gt;
&lt;p&gt;For this project, I once again picked shadow-cljs, so the project can be created with &lt;code&gt;npx create-cljs-project wave-function-collapse&lt;/code&gt;.
But before actually working with images we can begin with a bit simpler to debug version of it which deals with an ordinary text.
This can be done in plain Clojure, but since we&amp;rsquo;ll later plug it into our page, let&amp;rsquo;s use &lt;code&gt;.cljs&lt;/code&gt; file.
We start by implementing our algorithm in the file &lt;code&gt;wfc.cljs&lt;/code&gt;, &lt;code&gt;wfc&lt;/code&gt; being short for wave function collapse.&lt;/p&gt;
&lt;p&gt;As I&amp;rsquo;ve explained in the previous section, we start by transforming an input into a set of rules for the algorithm.
Our input will be a two-dimensional matrix, in this case, an array of arrays of strings.
Let&amp;rsquo;s start with a similar sample to that I&amp;rsquo;ve shown in the &lt;a href=&#34;#figure--example&#34;&gt;previous example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s even simpler, as it doesn&amp;rsquo;t have tiles that represent corners.
The first thing we need to do is to define a function, that gets all neighboring cells in all cardinal directions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-neighbors&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;dec &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;inc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)]}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;keep&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;when-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;}]))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function gets only those cells inside our matrix and discards those that are outside of its boundaries.
With this function we can write a function that builds a recipe from the input sample:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; add [clojure.set :as set] to :require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-recipe&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-indexed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-indexed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neigbors&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:keys&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;]}]] [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;}]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-neighbors&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               {&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neigbors&lt;/span&gt;})) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flatten&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply merge-with &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;merge-with &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set/union&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%1&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;map-indexed&lt;/code&gt; because we need to get neighbors for each cell, and this is what our &lt;code&gt;get-neighbors&lt;/code&gt; function accepts.
Calling this function on the &lt;code&gt;coast&lt;/code&gt; recipe yields the following map:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟫&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:up&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:down&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:left&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:right&lt;/span&gt; #{&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟦&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;🟩&amp;#34;&lt;/span&gt;}}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we have a proper illustration of the adjacency rules we&amp;rsquo;ve talked about before.
With that, we can start implementing the algorithm itself.&lt;/p&gt;
&lt;h2 id=&#34;collapsing-cells&#34;&gt;Collapsing cells&lt;/h2&gt;
&lt;p&gt;In order to collapse anything, we need a world in which we&amp;rsquo;ll do our work.
The beauty of this algorithm lies in the fact that it can work with a partially filled world, but generally, the world starts in a so-called superposition.
To get this superposition, we need to analyze the input sample once again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-superposition&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;#{} (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flatten&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives us all possible variants for a single cell.
To define a world we can just generate a new &amp;ldquo;empty&amp;rdquo; matrix that we&amp;rsquo;ll later populate with a cell superposition state.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;gen-world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;max-x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;max-y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;max-x&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;max-y&lt;/span&gt;)] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;populate-world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;superpos&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-superposition&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nil? &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;superpos&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As the last preparation step, we need a way of checking if the world is fully built.
This can be done by checking if any of the cells is still a hash-set and not a concrete value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;not &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;some &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set?&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;flatten&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A more optimal way would be to track how many cells were fully collapsed and compare it with the world size to avoid walking the whole world repeatedly on each step, but for now, this will do.
The last preparation step we need to do is to write a function that chooses which cell to collapse next.
The first cell can be selected at random, but the following must be selected more carefully, or we&amp;rsquo;ll corner ourselves pretty quickly.
To do that we need to measure world entropy and select a cell with the lowest one.
Since every cell can only contain a set of unique elements, we can measure the entropy by counting the number of elements in a cell.
Thus, a function that returns the lowest entropy cell can be defined as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lowest-entropy-cell&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enthropies&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-indexed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;keep-indexed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;) [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]])) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;concat&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shuffle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;sort-by &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;first&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enthropies&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;second &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [0 0])))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will produce uniform distribution, so we might want to change it a bit later, but for now, it&amp;rsquo;ll do.&lt;/p&gt;
&lt;p&gt;Now to the meat and bones of the algorithm.
To actually collapse a cell we need a function that can choose a random element of a cell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;1 (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;assoc-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;val&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After the cell is collapsed, we need to constrain its neighbors, so their superposition only contained possible elements that can be connected to this cell.
This is a bit harder part of the algorithm, as it involves waling a grid of cells recursively and constraining every cell that is a set and skipping others that are not.
If a cell itself is a set, its content should be treated as a series of cells that also affect how the surrounding cells should be constrained:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse-neighbors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neighbors&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-neighbors&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neighboring-cells&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;shuffle&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vals &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neighbors&lt;/span&gt;))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ❶&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&amp;#39; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reduce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt; {[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt;] &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:pos&lt;/span&gt;}]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pos&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ❷&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;variants&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set/intersection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;coll?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;set &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) #{&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set/union&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt;]) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;dir&lt;/span&gt;])))] &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ❸&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;and &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;variants&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;variants&lt;/span&gt;) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ❹&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neighbors&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse-neighbors&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;&amp;#39; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;neighboring-cells&lt;/span&gt;)))) &lt;span style=&#34;color:#888;font-style:italic&#34;&gt;; ❺&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is the heart of the algorithm, as it does all of the heavy liftings on constraining cells, so let&amp;rsquo;s break it down.
First, we get all neighbors and extract a sequence of cells that we&amp;rsquo;re going to constrain (❶).
We then iterate over these neighbors inside &lt;code&gt;reduce&lt;/code&gt;, getting the current world state for this cell (❷).
For this cell, we need to compute all remaining variants.
This is done by intersecting this cell&amp;rsquo;s state with variants from a neighbor in a given direction.
And if the cell itself is a set, this is done for each element in a set (❸).
Finally, a cell is collapsed (❹), except when it was a set and the variant list wasn&amp;rsquo;t empty.&lt;/p&gt;
&lt;p&gt;After that process is done for all four neighbors, we need to repeat it for each of the neighbors&amp;rsquo; neighbors.
So we check if our last run actually produced any change in the world, and if it is, we recursively walk through these neighbors (❺), otherwise, we return current world state.
This may actually cause a stack overflow error if there are too many neighbors to collapse, which depends both on the world size and how general the recipe is.
To avoid that, this function can be turned into iterative, but it still will maintain the stack of neighbors to collapse, which will grow in memory, instead of on a stack.
I&amp;rsquo;ve decided to go with recursion, as it&amp;rsquo;s a bit easier to understand in the context of the post.&lt;/p&gt;
&lt;p&gt;The last bit needed is a loop that will repeat this process until the whole world is collapsed.
The process is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pick a cell with the lowest entropy, first one is random&lt;/li&gt;
&lt;li&gt;collapse it&lt;/li&gt;
&lt;li&gt;constrain neighbors&lt;/li&gt;
&lt;li&gt;check if not done
&lt;ul&gt;
&lt;li&gt;repeat&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-recipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;populate-world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;] [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;))]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if-not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rand-nth&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse-neighbors&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lowest-entropy-cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, we can actually try it!
Let&amp;rsquo;s create some helpers, that will print the resulting world, and the input recipe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; add [clojure.string :as str] to :require&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-sample&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/join&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/join&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;] (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ([&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sep&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;) &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/join&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sep&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;str/join&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;println&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-result&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample:&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;println &lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;gen:&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;print-world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we use our &lt;code&gt;coast&lt;/code&gt; recipe, we should see this in our REPL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wfc.wfc&amp;gt; (print-result coast (wfc (gen-world 16 16) coast))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sample:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟩🟩🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟩🟦🟦🟩
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟫🟩🟫🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟫🟩🟦🟩🟫🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟫🟩🟦🟦🟦🟩🟫🟫🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟫🟩🟦🟦🟦🟦🟦🟩🟩🟫🟫🟫🟫
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟫🟩🟦🟦🟦🟦🟦🟦🟦🟦🟩🟫🟩🟩
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟫🟫🟩🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟩🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟩🟩🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can try with a bit more interesting examples, like these trees:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;def &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;snowy-trees&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [[&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;╱&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;╲&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;╱&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;╲&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   [&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;╱&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;v&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;╲&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wfc.wfc&amp;gt; (print-result snowy-trees (wfc (gen-world 16 60) snowy-trees))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sample:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*    *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  *╱╲ *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* ╱vv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ╱vvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *  *  *   *   *      *   *     *    *   *  * *    * *  *  *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   *  *  *    * * * *   *  * *    *    *     *  * * *  *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *      *      *              *  *       * *   *   *  * * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  * * *   *   * * *  * *  *     *    * *  *   * *      * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *   *   *   * *   *  *  *  * *  *  *   *  * * * *        *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   *    *  *      *       *  *  *  *  *  *    * * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *        * * *  *  *  * *     *  * *     * *      * * * * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  *  *  *    *  * *  *     *  *  * *  *  * *    *   *   * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         * *   * * *      *    *  *     * *  * *  ╱╲  *  *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   *  * * *   *       *  *    *      *        * *╱vv╲  *   *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*   *  *   * *     * * *   *     *  *  * *  *  *╱vvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  *   *   * *   * *     *   *   *  *    * *  * ╱vvvvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *  *   *     *   ╱╲ *    *   *   *  ╱╲  *  * ╱vvvvvvvv╲ *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         *     * ╱vv╲ *  *  ╱╲ * * *╱vv╲   * ╱vvvvvvvvvv╲ *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *   *     *    ╱vvvv╲  * *╱vv╲ * *╱vvvv╲ * ╱vvvvvvvvvvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*  ╱╲ *  ╱╲  * ╱vvvvvv╲   ╱vvvv╲ *╱vvvvvv╲ ╱vvvvvvvvvvvvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Noticeable, the spread is too uniform.
This is because we pick a random choice, and the choices have equal distribution.
Instead, it&amp;rsquo;d be nicer if we had a bit more control over what elements are more present and what is less present.&lt;/p&gt;
&lt;p&gt;To do that, we need to replace our random choice picking with weighted random.
First, we need to calculate the weights:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-weights&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;frequencies&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will do - the more times a certain tile appears in a recipe, the higher its weight is.
Now we need a weighted random:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weighted-random&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;variants&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce &lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;assoc &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;k&lt;/span&gt;))) {} &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;elements&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reductions&lt;/span&gt; #(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%2&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;vals &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;variants&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rnd&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;last &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;nth &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;keys &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;variants&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;take-while &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;&amp;lt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rnd&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now, that we have weights, we can upgrade our &lt;code&gt;lowest-entropy-cell&lt;/code&gt; function to take weights into account when calculating the entropy.
We also use a better entropy calculation algorithm, based on &lt;a href=&#34;https://en.wikipedia.org/wiki/Entropy_%28information_theory%29&#34; target=&#34;_blank&#34;&gt;Shannon entropy:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell-enthropy&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weight-sum&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce + &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log-weight-sum&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce + &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;map &lt;/span&gt;#(&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weight&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                         (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weight&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Math/log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;double &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weight&lt;/span&gt;)))) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;Math/log&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;- &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weight-sum&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;log-weight-sum&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weight-sum&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lowest-entropy-cell&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enthropies&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;map-indexed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;keep-indexed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell-enthropy&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;) [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;]])) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;r&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;reduce into &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sorted-map&lt;/span&gt;)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;if-some&lt;/span&gt; [[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;] (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;enthropies&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [0 0])))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last change needed is in the &lt;code&gt;wfc&lt;/code&gt; function - we need to use &lt;code&gt;weighted-random&lt;/code&gt; when we &lt;code&gt;collapse&lt;/code&gt; a cell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;build-recipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-weights&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;populate-world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;] [(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;rand-int &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;count &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;))]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;if-not &lt;/span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;done?&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;get-in&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weighted-random&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;collapse-neighbors&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recipe&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lowest-entropy-cell&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;weights&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the algorithm is done, and we can see that the &lt;code&gt;snowy-trees&lt;/code&gt; example has a bit less snow now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wfc.wfc&amp;gt; (print-result snowy-trees (wfc (gen-world 16 60) snowy-trees))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sample:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*    *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  *╱╲ *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* ╱vv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ╱vvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gen:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   *    *    *   *  *       *      *           * *         *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  *        *    *         *     *       *       * *   * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       *      *        *   *         *    *   *    *   *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   *                *        *     *  *    *     *   *   *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*             *  * *      *          *       *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           *           *   *    *       * *             *  *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              *  *    *            *   *      *      *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    *     *  *     * *     *    *    *     *           * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   * *     *          * *   *  *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          *    *       *  *       *   * *   *     *  * *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  * *       * *    * *   *     *   * * *            *   *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       *   *    *                 *      *        ╱╲ *     *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      *      *        * *            *      *  * ╱vv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     * ╱╲            *    * *          *  *     ╱vvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ╱vv╲   ╱╲  *       *      *        *  *  ╱vvvvvv╲
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  *  ╱vvvv╲ ╱vv╲   ╱╲  *  * *           * *  *╱vvvvvvvv╲  *╱
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;working-with-images&#34;&gt;Working with images&lt;/h2&gt;
&lt;p&gt;At the beginning of this article, I&amp;rsquo;ve shown you an image of a coast.
This image is generated by the code above, but right now it can&amp;rsquo;t handle images, only text.
This isn&amp;rsquo;t a problem, really, because the text is just used in place of unique identifiers, so we can plug in anything, and then use the resulting world as a recipe to paint it on a canvas.
Let&amp;rsquo;s do exactly that, but before we can do it, we need to be able to upload an image and splice it into tiles.&lt;/p&gt;
&lt;p&gt;To do that, we&amp;rsquo;ll need an &lt;code&gt;index.html&lt;/code&gt; file in our &lt;code&gt;public/&lt;/code&gt; directory, and a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; tag in it with an appropriate &lt;code&gt;id&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;canvas id=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample_view&amp;#34;&lt;/span&gt; width=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;512&amp;#34;&lt;/span&gt; height=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;512&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/canvas&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;input type=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample_input&amp;#34;&lt;/span&gt; accept=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;image/*&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/input&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;script type=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; src=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;/js/main.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;window&lt;/span&gt;.onload = &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    wfc.core.init();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m also adding an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; tag, to open an image.
Additionally to that, there should be the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag that loads our &lt;code&gt;core&lt;/code&gt; module and runs the &lt;code&gt;init&lt;/code&gt; function.
With this in place, we can add an event listener to the button, and load the image to canvas.
In &lt;code&gt;core.cljs&lt;/code&gt; add:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:export&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;init&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-input&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample_input&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-input&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;change&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/upload&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And in &lt;code&gt;sample.cljs&lt;/code&gt; create the &lt;code&gt;upload&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defonce &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dynamic&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:image&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; 0})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;viewer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample_view&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/Image.&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getContext&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;viewer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;fn &lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt; {&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:image&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                     &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;viewer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;viewer&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.clearRect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; 0 0 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;viewer&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;viewer&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.drawImage&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; 0 0)))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;load&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-src&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-result&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;upload&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;files&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-target&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-files&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/FileReader.&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;load&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.readAsDataURL&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;reader&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;aget &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;files&lt;/span&gt; 0)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should allow us to upload an image.
Now we need to split it into tiles.
To do that, let&amp;rsquo;s add another button to our &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;button type=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;split_to_tiles&amp;#34;&lt;/span&gt;&amp;gt;Split to tiles&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In &lt;code&gt;core.cljs&lt;/code&gt; we add another event listener:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:export&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;init&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-input&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample_input&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-input&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;change&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/upload&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tile-size&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;split_to_tiles&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tile-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;click&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/split-to-tiles&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render-button&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render-button&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;click&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render/render&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And define the function that does the work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defonce &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dynamic&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*sample*&lt;/span&gt; [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defonce &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:dynamic&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*tiles*&lt;/span&gt; {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;split-to-tiles&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:image&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.createElement&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;canvas&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt;) (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getContext&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.drawImage&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:image&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt;) 0 0)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hashes-imgs&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt;) 32)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;for &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;range &lt;/span&gt;0 (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*image*&lt;/span&gt;) 32)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;img&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getImageData&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 32 32)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            [(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hash&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;vec&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;img.data&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;img&lt;/span&gt;])))]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*sample*&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; #(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;mapv&lt;/span&gt; &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;first &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;%&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hashes-imgs&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;set!&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;*tiles*&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;into &lt;/span&gt;{} (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;apply concat &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;hashes-imgs&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/alert&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Please upload an image first&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We do basic error checking, that an image was uploaded by checking &lt;code&gt;*image*&lt;/code&gt; to have anything under the &lt;code&gt;:image&lt;/code&gt; key.
If there&amp;rsquo;s an image, we create a canvas, that we draw this image on, and then iterate thru it row by row, tile by tile, with a fixed tile size of &lt;code&gt;32&lt;/code&gt;.
In this loop, we get an array of pixels, representing the given tile, and we calculate its hash, which we will use in our wave function collapse algorithm.&lt;/p&gt;
&lt;p&gt;Now we can upload an image, and split it into tiles, the only thing left is to actually draw the result!&lt;/p&gt;
&lt;h2 id=&#34;drawing-the-result&#34;&gt;Drawing the result&lt;/h2&gt;
&lt;p&gt;We need yet another canvas for that.
Actually, we need only one canvas for all of this, as we have the input button that takes care of image loading, and another button for splitting.
But I still like to see what sample is loaded, as it gives a better understanding of what the resulting image was constructed from.
So let&amp;rsquo;s add another canvas and a button:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;canvas id=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;render_view&amp;#34;&lt;/span&gt; width=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;512&amp;#34;&lt;/span&gt; height=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;512&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/canvas&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;button type=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;&amp;gt;Generate&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once again, let&amp;rsquo;s add a handler to this button in &lt;code&gt;core.cljs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.render&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;^&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:export&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;init&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-input&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;sample_input&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample-input&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;change&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/upload&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tile-size&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;split_to_tiles&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tile-size&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;click&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/split-to-tiles&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render-button&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.addEventListener&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render-button&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;click&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render/render&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And in &lt;code&gt;render.cljs&lt;/code&gt; we need to define the &lt;code&gt;render&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.render&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.sample&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc.wfc&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:as&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;render&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;_&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:image&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/*image*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;renderer&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getElementById&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/document&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;render_view&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getContext&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;renderer&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;2d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;renderer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;renderer&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.clearRect&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; 0 0 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;solve&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/alert&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Please upload an image&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing too complicated, just a handler that clears the canvas and calls &lt;code&gt;solve&lt;/code&gt;.
Now, &lt;code&gt;solve&lt;/code&gt; is where the work is done:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;solve&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;seq &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/*sample*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tiles&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/*tiles*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; 32]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc/wfc&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;wfc/gen-world&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;width&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;height&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;sample/*sample*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rows&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;world&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;font-weight:bold&#34;&gt;loop &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; 0]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;when-let &lt;/span&gt;[[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt; &amp;amp; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cells&lt;/span&gt;] &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;row&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;get &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;tiles&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cell&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;cells&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;recur&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;rows&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;+ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/alert&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;Please split image to tiles&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First, we compute the result with &lt;code&gt;wfc&lt;/code&gt; call, and then we iterate over it calling &lt;code&gt;draw&lt;/code&gt; for each cell.
The tile is retrieved from the &lt;code&gt;*tiles*&lt;/code&gt; variable, we&amp;rsquo;ve set in &lt;code&gt;sample.cljs&lt;/code&gt; when we split the image.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;draw&lt;/code&gt; function is simple - it accepts an image, coordinates where we need to draw it, the size, and the canvas&amp;rsquo; context.
Then it just draws the image:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;draw&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;let &lt;/span&gt;[&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;js/Uint8ClampedArray.&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;image.data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;place&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.getImageData&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;size&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.set&lt;/span&gt; (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.-data&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;place&lt;/span&gt;) &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;arr&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;.putImageData&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;place&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;y&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result will probably look a bit different, but the general idea is the same:&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;sample_view&#34; width=&#34;192&#34; height=&#34;160&#34; style=&#34;background-color: #888&#34;&gt;&lt;/canvas&gt;
&lt;br&gt;
&lt;input type=&#34;file&#34; id=&#34;sample_input&#34; accept=&#34;image/*&#34;&gt;&lt;/input&gt;
&lt;br&gt;
&lt;button type=&#34;button&#34; id=&#34;split_to_tiles&#34;&gt;Split to tiles&lt;/button&gt;
&lt;br&gt;
&lt;br&gt;
&lt;canvas id=&#34;render_view&#34; width=&#34;256&#34; height=&#34;256&#34; style=&#34;background-color: #888&#34;&gt;&lt;/canvas&gt;
&lt;br&gt;
&lt;br&gt;
&lt;button type=&#34;button&#34; id=&#34;render&#34;&gt;Generate&lt;/button&gt;&lt;/p&gt;
&lt;script type=&#34;text/javascript&#34; src=&#34;https://andreyor.st/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/js/main.js&#34;&gt;&lt;/script&gt;
&lt;script&gt;
  window.onload = function() {
    wfc.core.init();
  }
&lt;/script&gt;
&lt;p&gt;You can use this image to try the whole process:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://andreyor.st/2022-05-10-wave-function-collapse-algorithm-in-clojurescript/coast.png&#34;
         alt=&#34;Figure 4: coast&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 4: &lt;/span&gt;coast&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Alternatively, you can try other samples, just beware that the tile size is fixed to 32x32 pixels.&lt;/p&gt;
&lt;h2 id=&#34;a-proper-demo&#34;&gt;A proper demo&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve actually omitted some more things on the JS side, as the post already got a bit to long even after we&amp;rsquo;ve finished the algorithm.
Things like configurable tile size, and custom world sizes, better error handling can be added, it&amp;rsquo;s just mostly the same stuff we already did for other buttons, and thus can get repetitive pretty quickly.
So instead I&amp;rsquo;ve set up a separate page with a better visuals, tile picker, editor, some additional examples to try, and more robust error handling.
You can try it &lt;a href=&#34;https://andreyor.st/wave-function-collapse/&#34;&gt;here&lt;/a&gt;.
And a bit more polished code can be found in the &lt;a href=&#34;https://gitlab.com/andreyorst/wave-function-collapse&#34; target=&#34;_blank&#34;&gt;repo&lt;/a&gt; for that demo page.&lt;/p&gt;
&lt;p&gt;I know that this isn&amp;rsquo;t how ClojureScript is used in production, but it&amp;rsquo;s still nice that you can build such pages pretty quickly, using your favorite language.
In the future I&amp;rsquo;ll probably learn some proper frontend related stuff, like Lumen or re-frame, but this is a thing for another time.
Hope this was an interesting read!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I&amp;rsquo;m saying lisp as in the language not as in concrete implementation.
To be clear, I&amp;rsquo;ve worked my way thru SICP, and mostly used Racked or GNU Guile, not Common Lisp, so I&amp;rsquo;m not biased on what is lisp, and I accept Clojure as a valid dialect, even if some may disagree.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;This includes &lt;a href=&#34;https://github.com/andreyorst/love-fabrik&#34; target=&#34;_blank&#34;&gt;LÖVE Fabrik&lt;/a&gt;, &lt;a href=&#34;https://andreyor.st/posts/2020-10-15-raymarching-with-fennel-and-love/&#34;&gt;raymarching&lt;/a&gt;, &lt;a href=&#34;https://andreyor.st/posts/2020-06-04-simple-ray-casting-with-clojurescript/&#34;&gt;raycasting&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;This is the approach I&amp;rsquo;ve taken when I&amp;rsquo;ve implemented my first Scheme-like language, condition-system, a library for asynchronous programming, raymarching algorithm, and many other projects.
I think I find this approach fascinating because when the thing finally works, and I go and look how it should be done, and see that I&amp;rsquo;ve got some things right, it gives me a lot of joy.
This also trains to think outside of the box, and solve problems that you don&amp;rsquo;t exactly know how to solve.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Wave Function Collapse Algorithm in ClojureScript&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 10 May 2022 08:20:00 +0300</pubDate>
    </item><item>
      <title>100% is the only acceptable test coverage</title>
      <link>https://andreyor.st/posts/2022-03-29-100-is-the-only-acceptable-test-coverage/</link>
      <guid>https://andreyor.st/posts/2022-03-29-100-is-the-only-acceptable-test-coverage/</guid>
      <description>&lt;p&gt;…kinda.&lt;/p&gt;
&lt;p&gt;I think that the only acceptable test coverage percentage is &lt;em&gt;about 100%&lt;/em&gt;.
And in this post, I&amp;rsquo;ll try to explain why I choose to believe it.&lt;/p&gt;
&lt;h2 id=&#34;why-test-coverage-matters&#34;&gt;Why test coverage matters&lt;/h2&gt;
&lt;p&gt;I have a lot of projects of various sizes.
In most cases, these projects are libraries, that I host publicly, and some tools I&amp;rsquo;ve written for myself only.
What&amp;rsquo;s common about these projects is that no matter if it&amp;rsquo;s a public project or my personal one, I&amp;rsquo;m trying to test those as well as I can.&lt;/p&gt;
&lt;p&gt;But this raises some important questions, one of which is how do we measure the quality of our tests?
A rather obvious answer to that question is test coverage.
And I can only say that this is the stupidest metric to measure test quality because coverage doesn&amp;rsquo;t actually guarantee that tests check all various corner cases data-wise.&lt;/p&gt;
&lt;p&gt;Test quality is a bit different topic, and while code coverage is not what measures it, it is still important, and in my opinion, the reasonable percentage is 100% or something really close to it.
I&amp;rsquo;ll explain why in a moment, but before that, I&amp;rsquo;ll address a question that probably has appeared in your head: &amp;ldquo;why go as high as 100%?&amp;rdquo;.
And that&amp;rsquo;s a valid question.&lt;/p&gt;
&lt;p&gt;Recently, I&amp;rsquo;ve talked with some developers who use different languages and was kinda surprised to hear that on average, the acceptable test coverage is ~60%.
Some say that writing unit tests for functions that are inherently simple is meaningless, as those can be verified fully at the stage of writing the function itself.
Others say that 60% is just enough to cover the public API and catch most of the bugs that the end-user may experience.
Some even say that test coverage doesn&amp;rsquo;t matter at all, and only integration coverage actually does, but it&amp;rsquo;s hard to count, so nobody really cares.
But even they agreed when I asked them if 60% would be enough for them.&lt;/p&gt;
&lt;p&gt;I disagree strongly.&lt;/p&gt;
&lt;p&gt;You may have heard of the 80/20 rule, also known as &lt;a href=&#34;https://en.wikipedia.org/wiki/Pareto_principle&#34; target=&#34;_blank&#34;&gt;Pareto principle&lt;/a&gt;.
The Wikipedia article I&amp;rsquo;ve linked has a section related to computer science, that states that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer science, the Pareto principle can be applied to optimization efforts.
For example, Microsoft noted that by fixing the top 20% of the most-reported bugs, 80% of the related errors and crashes in a given system would be eliminated.
Lowell Arthur expressed that &amp;ldquo;20% of the code has 80% of the errors.
Find them, fix them!&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And after a while of writing tests and measuring code coverage for my projects, I noticed something similar to that.
&lt;strong&gt;The last 20% of code coverage held 80% of bugs of the code.&lt;/strong&gt;
And the interesting part was, that no matter how good my tests were, it didn&amp;rsquo;t matter, as they weren&amp;rsquo;t touching the parts of the code that actually had unnoticed bugs.
So whenever I&amp;rsquo;ve stopped at code coverage of 80% saying to myself that this is good enough, I was lying to myself, as it clearly wasn&amp;rsquo;t.&lt;/p&gt;
&lt;h2 id=&#34;what-code-coverage-is-about&#34;&gt;What code coverage is about&lt;/h2&gt;
&lt;p&gt;So, now let me address some misconceptions about code coverage.&lt;/p&gt;
&lt;p&gt;Foremost, test coverage is &lt;strong&gt;not about&lt;/strong&gt; covering &lt;strong&gt;every function&lt;/strong&gt; in your project with a unit test.
This is pointless extra work that will be negated with the first tiny code refactoring.
Because of that, all these tests will become obsolete, and new tests are likely won&amp;rsquo;t be ever written, because why bother, if they&amp;rsquo;ll become irrelevant with the next refactoring?
And functions are really simple, why even test those?&lt;/p&gt;
&lt;p&gt;Second, for those who love numbers, 60% coverage in a project with just 2k lines of code (LOC) means, that 800 lines were never even touched by the existing tests.
In a project with 10k LOC, it&amp;rsquo;s already 4k lines.
Not only you can&amp;rsquo;t reason about correctness, but you also can&amp;rsquo;t tell what&amp;rsquo;s actually used in your project and what&amp;rsquo;s not!&lt;/p&gt;
&lt;p&gt;And &lt;strong&gt;that&amp;rsquo;s&lt;/strong&gt; the point of code coverage - telling you what parts of your application/library are not reachable from the public API that you always must test.
You &lt;strong&gt;don&amp;rsquo;t need&lt;/strong&gt; to write unit tests for anything but the public API in almost all cases!
Yes, it&amp;rsquo;s good to write tests that check complex functions, which do some data transformation for example, with a lot of different test inputs - I&amp;rsquo;m not against that at all.
However, if you write a unit test for a private function, think of it for a moment, maybe you&amp;rsquo;re doing something wrong.&lt;/p&gt;
&lt;p&gt;As of this moment, I&amp;rsquo;m mainly using two languages - Fennel and Clojure, and the part about testing private functions is what makes these languages a bit different for me when I&amp;rsquo;m reasoning about code and its public API.
The difference is that in Fennel there&amp;rsquo;s no way of accessing a private function of a module, and hence there&amp;rsquo;s no way to test it directly.
In Clojure, there is, and when I see, or even have to use &lt;code&gt;(#&#39;some-ns/some-private-fn)&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; in a test, it&amp;rsquo;s a huge red flag for me, that something is not right in the application code itself.
Fennel (actually Lua) doesn&amp;rsquo;t have this problem, because if something is declared as &lt;code&gt;local&lt;/code&gt; in a script file and not exported from it in a table, that&amp;rsquo;s that - you can&amp;rsquo;t have it.&lt;/p&gt;
&lt;p&gt;So when writing tests in Fennel or Lua, your only option is to test exported functions only, which is a kind of your public API.
And if you wrote tests, and see that all lines are covered, all expressions are visited, and you still can&amp;rsquo;t reach some private functions - well, that&amp;rsquo;s a clear indication of a dead code.
Dead code is bad because it rots even if you don&amp;rsquo;t touch it.
Even more - if you actually go and write unit tests for such dead code, you&amp;rsquo;ll make the situation even worse for yourself in the long run.
After a certain period, these tests may be the reason you can&amp;rsquo;t move forward, because you&amp;rsquo;ll be afraid to change or even remove a code that &lt;em&gt;appears&lt;/em&gt; to be unused - but you can&amp;rsquo;t be sure, because there are tests for this code.&lt;/p&gt;
&lt;p&gt;Now, I know what you can say to this - modern IDEs can detect unused code by using static analysis.
This is a great feature that helps to deal with this problem to some degree.
First, some IDEs detect that code is used in tests, and that&amp;rsquo;s enough for them to consider code not to be dead, which isn&amp;rsquo;t actually true.
It is an important feature, but not a silver bullet, and not all languages have it.
Yes, in most cases it helps you see that some code is indeed unused, but that&amp;rsquo;s the only thing it does.
Test coverage also shows that, plus provides additional correctness guarantees of your code because of tests that you&amp;rsquo;ve written.&lt;/p&gt;
&lt;h2 id=&#34;why-100-is-not-always-possible&#34;&gt;Why 100% is not always possible&lt;/h2&gt;
&lt;p&gt;I hope you now see why I think why code coverage is very important.
But percentage doesn&amp;rsquo;t exactly say to you what is left uncovered, so all code coverage tools provide some kind of report, usually in a color-coded form.
Some coverage tools build interactive web pages that allow easy project navigation, and some just print results to &lt;code&gt;stdout&lt;/code&gt; using ANSI color codes.
Both are equally helpful because you see the results of your work.&lt;/p&gt;
&lt;p&gt;However, unfortunately, it&amp;rsquo;s not as simple as that.
If it had been, I guess the average coverage percentage &lt;em&gt;expectage&lt;/em&gt; would be higher than 60%.
So what can cause problems?&lt;/p&gt;
&lt;p&gt;If you test an application, then in many cases you probably can&amp;rsquo;t test the &lt;code&gt;main&lt;/code&gt; function, especially when it starts a server for example.
This means, that the entry point to your application is untested, and this might cause problems in the future.
As a workaround, it is possible to mock the server starting functions so &lt;code&gt;main&lt;/code&gt; would return immediately.
This, probably, won&amp;rsquo;t return any meaningful values for the test itself, but you&amp;rsquo;ll be able to see what parts of code are triggered by the initialization process and see if there are some dead parts.
Alternatively, if all the main function does is initialization and service startup, these things can be tested separately, and &lt;code&gt;main&lt;/code&gt; can be excluded from testing, but this will lower the coverage percentage, as expected.&lt;/p&gt;
&lt;p&gt;Another problem is again solvable with mocks but seems to defeat the purpose of testing.
It does not.
I&amp;rsquo;m talking about interactions with external services.
A common misconception is that by mocking the server, we create an ideal model that doesn&amp;rsquo;t help at unit testing.
While this is somewhat true, it also depends on &lt;em&gt;how you mock it&lt;/em&gt;.
You can write such a mock that causes a timeout, or a mock that sends invalid or corrupted data to test error recovery.
You can even write a small service inside your codebase that mimics the public API of a real one, which can help with testing.
And with mock-based testing, your application code can mostly consist of private definitions, as you don&amp;rsquo;t need to export those for testing.&lt;/p&gt;
&lt;p&gt;This is something in between integration and unit testing, and while it&amp;rsquo;s surely not as good as real integration testing, it is still something worth doing.
Your public API probably won&amp;rsquo;t change as much as your code, and you&amp;rsquo;ll be more certain that nothing broke if you have such tests.
This is also a very good way of seeing what parts of your code in the coverage report are touched sorely by interacting with external services, without manually patching in the data for transformation.
Though I must say that writing mocks for every network problem imaginable is not an easy or even impossible task, it&amp;rsquo;s not always a solution.&lt;/p&gt;
&lt;h3 id=&#34;expression-and-line-coverage&#34;&gt;Expression and line coverage&lt;/h3&gt;
&lt;p&gt;The last main problem is that coverage tools are not always accurate.
This includes some quirks in the language runtime or tooling, that prevent it from tracking all lines or expressions.
I often see this in Lua, when I run some tests, collect coverage reports and see some branches as not being hit.
I then add a &lt;code&gt;print&lt;/code&gt; call to these branches and see prints in the output, meaning that the code is indeed touched by the test.
But the coverage tool doesn&amp;rsquo;t register it for some reason, and that particular call to &lt;code&gt;print&lt;/code&gt; is shown as uncovered.&lt;/p&gt;
&lt;p&gt;And the line-or-expression distinction in the coverage report is another problem with the opposite outcome.
If the previous problem was about the impossibility of achieving 100% because some code just won&amp;rsquo;t register, this is about achieving 100% without hitting all code.
The reason for that is that if you put multiple expressions on the same line, a coverage tool that doesn&amp;rsquo;t know about expressions may show a completely wrong coverage.
Here&amp;rsquo;s an oversimplified example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-lua&#34; data-lang=&#34;lua&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- lib.lua&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  f = &lt;span style=&#34;font-weight:bold&#34;&gt;function&lt;/span&gt; (a, b)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;if&lt;/span&gt; a == 10 &lt;span style=&#34;font-weight:bold&#34;&gt;then&lt;/span&gt; res = a * b &lt;span style=&#34;font-weight:bold&#34;&gt;else&lt;/span&gt; res = a / b &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; res
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;-- lib_test.lua&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; lib = require &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;lib&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;local&lt;/span&gt; res = lib.f(10, 20)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;assert(res == 200, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;expected 200, got &amp;#34;&lt;/span&gt; .. res)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;if&lt;/code&gt; statement in the function &lt;code&gt;f&lt;/code&gt; is written as a one-liner (for this particular example reasons).
The test only checks one specific case, which can only trigger the true branch of the &lt;code&gt;if&lt;/code&gt;.
There are no tests for false branch, which may easily result in a division by zero if &lt;code&gt;a&lt;/code&gt; is not &lt;code&gt;10&lt;/code&gt;, and &lt;code&gt;b&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;.
While this is not a problem in Lua, as it will just return &lt;code&gt;inf&lt;/code&gt;, this may be a problem for your application, which will not know what to do with infinity.&lt;/p&gt;
&lt;p&gt;This is an exaggerated example, only meant as an illustration of the problem.
Running the test module with &lt;a href=&#34;https://keplerproject.github.io/luacov/&#34; target=&#34;_blank&#34;&gt;Luacov&lt;/a&gt; shows a 100% coverage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lua -lluacov lib_test.lua &amp;amp;&amp;amp; luacov-console &amp;amp;&amp;amp; luacov-console -s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==============================================================================
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Summary
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==============================================================================
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;File         Hits Missed Coverage
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lib.lua      4    0      100.00%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lib_test.lua 4    0      100.00%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Total        8    0      100.00%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thankfully, I write my code in Fennel, and it usually generates a somewhat well-formatted Lua code, so coverage is more or less accurate.
Doing the same with Clojure won&amp;rsquo;t have this problem at all, because &lt;a href=&#34;https://github.com/cloverage/cloverage&#34; target=&#34;_blank&#34;&gt;Cloverage&lt;/a&gt; provides two separate statistics - line coverage and form coverage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; src/lib/core.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib.core&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;font-weight:bold&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; 10) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;* &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;) (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;/ &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;b&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;;; test/lib/core.clj&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;ns &lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib.core-test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:require&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;clojure.test&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:refer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deftest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;lib.core&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;:refer&lt;/span&gt; [&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt;]]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;deftest&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f-test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;is&lt;/span&gt; (&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;= &lt;/span&gt;200 (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;f&lt;/span&gt; 10 20))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see, I&amp;rsquo;ve done the same thing as in Lua, but the coverage report suggests that something is not right:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lein cloverage
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------+---------+---------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Namespace | % Forms | % Lines |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------+---------+---------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|  lib.core |   75.00 |  100.00 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------+---------+---------|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| ALL FILES |   75.00 |  100.00 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-----------+---------+---------|
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, the main point I wanted to show here is that not all coverage percentage reports are fully trustable, that&amp;rsquo;s why the visual report is important.
Seeing a pretty long line with an &lt;code&gt;if&lt;/code&gt; statement in Lua should tell you to be more careful with this code, as some parts of the code could have not been touched.
Cloverage colors such line in orange, meaning that not all forms were covered, but doesn&amp;rsquo;t tell you which forms weren&amp;rsquo;t touched.
Both cases can be fixed with the proper formatting.&lt;/p&gt;
&lt;h2 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h2&gt;
&lt;p&gt;Overall, I hope I was able to convince you that 60% code coverage is far from ideal and that 80% is still not enough.
In my personal opinion, something starting from 97% is a way to go.
Of course, it&amp;rsquo;s not always possible, but when it is, there&amp;rsquo;s no reason not to go for it.
And I&amp;rsquo;ll repeat myself, having higher coverage percentage doesn&amp;rsquo;t mean your code is well tested, it&amp;rsquo;s merely well covered.&lt;/p&gt;
&lt;p&gt;To summarize - test your public API and collect coverage of it specifically.
Having 100% code coverage achieved through such testing means that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There&amp;rsquo;s no dead code.&lt;/li&gt;
&lt;li&gt;You have tests for everything in your application/library.&lt;/li&gt;
&lt;li&gt;You have a very reasonable starting point for improving all tests with more cases.
&lt;ul&gt;
&lt;li&gt;And because of that, there are more possibilities to find bugs in some far-to-reach places (80/20 rule).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve already said that I&amp;rsquo;m against writing unit tests for private functions, but, well, see for yourself.
I, personally, think that this means that the code was meant to be public, and making it private was a design mistake.
But your view may vary.&lt;/p&gt;
&lt;p&gt;While 100% coverage may not be always possible, carefully observe what kind of code was not covered.
If that&amp;rsquo;s something because the coverage calculation tool just misbehaves, well, there&amp;rsquo;s little you can do with it.
If that&amp;rsquo;s due to the inability to test something like a &lt;code&gt;main&lt;/code&gt; function, or a very tricky part that communicates with another service - make sure it&amp;rsquo;s well tested through integration testing.
Everything else, probably means you have some potentially incorrect design decisions that should be corrected.&lt;/p&gt;
&lt;p&gt;Hope this was an interesting read, feel free to share your thoughts on the topic and tag me in any of the &lt;a href=&#34;https://andreyor.st/about/#links&#34;&gt;social networks&lt;/a&gt; if you disagree or have something to discuss on the topic!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;This is how you access a private var in Clojure.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: 100% is the only acceptable test coverage&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 29 Mar 2022 18:09:00 +0300</pubDate>
    </item><item>
      <title>Generic* tuples in C</title>
      <link>https://andreyor.st/posts/2022-03-15-generic-tuples-in-c/</link>
      <guid>https://andreyor.st/posts/2022-03-15-generic-tuples-in-c/</guid>
      <description>&lt;p&gt;A day ago I was asked if it&amp;rsquo;s possible in C to make some preprocessor macro that will create a &lt;a href=&#34;https://en.wikipedia.org/wiki/Product_type&#34; target=&#34;_blank&#34;&gt;tuple object&lt;/a&gt; from something like &lt;code&gt;tuple(a, b, c)&lt;/code&gt;.
I&amp;rsquo;m not writing in C actively anymore, since I switched to Clojure some years ago, but I still like to poke with C from time to time.
I&amp;rsquo;ve thought to myself, that this should be doable via macros, and decided to try it out.
However, the C preprocessor is not the best way to write macros, yet unfortunately, it&amp;rsquo;s our only option.&lt;/p&gt;
&lt;p&gt;So what is our goal here?
A tuple is usually a fixed-size data structure that (often) can be indexed, and can contain elements of various types.
And because of that, it may be a bit tricky to do it in C because C doesn&amp;rsquo;t have a lot of tools for deducing type or generating code.
So in theory, something like a generic fixed-size array that can store elements of an arbitrary type will work fine.
And the only needed is to make a proper container for elements and write some macros to automate things.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve marked &amp;ldquo;generic&amp;rdquo; in the title with an asterisk, because, well, it&amp;rsquo;s C, there is no support for generics aside from the &lt;code&gt;_Generic&lt;/code&gt; dispatcher and, well, macro concatenation.
In this post, I&amp;rsquo;ll explain two solutions I&amp;rsquo;ve come up with, but both have their own constraints.
The first implementation below kinda allows for any type to be used as an element but requires adding new types every time you want something else.
The second implementation is more approachable, as it requires you to pre-define the type of the resulting tuple before you could use it.
So it&amp;rsquo;s not like true generics, but (I think) a close approximation.&lt;/p&gt;
&lt;h2 id=&#34;take-1-union-structs&#34;&gt;Take 1 - Union structs&lt;/h2&gt;
&lt;p&gt;Luckily for me, I&amp;rsquo;ve already experimented with &amp;ldquo;recursive&amp;rdquo; macros in C in my previous work, so I knew what to do.
In theory.
My initial thought was to generate an array of union structs.
Each struct would contain a &lt;code&gt;union&lt;/code&gt;, which would hold all possible types, and a &lt;code&gt;type&lt;/code&gt; field that would just tell us what type this particular union is.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#pragma once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; TupleItemType {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LONG,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DOUBLE,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    STRING,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;enum&lt;/span&gt; TupleItemType type;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;               pad[4];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;union&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;long&lt;/span&gt;   i32;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt; f64;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt; * string;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 1:&lt;/span&gt;
  File: &lt;code&gt;tuple.h&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;For now, I&amp;rsquo;ve decided to go with only three types, as it is easy to add more.
I&amp;rsquo;ve also created a &lt;code&gt;Tuple&lt;/code&gt; struct, that holds a pointer to an array of &lt;code&gt;TupleItem&lt;/code&gt; and its size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt;       size;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;               pad[4];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem * tuple;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 2:&lt;/span&gt;
  File: &lt;code&gt;tuple.h&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;With that we can try to use it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;#34;tuple.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pprint_tuple_item&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem * x);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pprint_tuple_item&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem * x) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;switch&lt;/span&gt; (x-&amp;gt;type) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; LONG: printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%ld&amp;#34;&lt;/span&gt;, x-&amp;gt;value.i32); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; DOUBLE: printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;%f&amp;#34;&lt;/span&gt;, x-&amp;gt;value.f64); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-weight:bold&#34;&gt;case&lt;/span&gt; STRING: printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, x-&amp;gt;value.string); &lt;span style=&#34;font-weight:bold&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pprint_tuple&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple * t);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;pprint_tuple&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple * t) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; i = 0; i &amp;lt; t-&amp;gt;size - 1; i++) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        pprint_tuple_item(&amp;amp;(t-&amp;gt;tuple[i]));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pprint_tuple_item(&amp;amp;t-&amp;gt;tuple[t-&amp;gt;size - 1]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem items[] = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem){.type = LONG, .value.i32 = 42},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem){.type = DOUBLE, .value.f64 = 22./7},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem){.type = STRING, .value.string = &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple tuple = {.tuple = items, .size = 3};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pprint_tuple(&amp;amp;tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 3:&lt;/span&gt;
  File: &lt;code&gt;main.c&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;Now, I know, that I shouldn&amp;rsquo;t create and pass arrays like that, but for now it&amp;rsquo;ll do.
With these helper functions in place, compiling and running this code yields an expected result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clang -MM --std=c99 -Wpedantic -Wextra -Weverything -Wall  *.c &amp;gt; .depend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clang -o main.o -c main.c --std=c99 -Wpedantic -Wextra -Weverything -Wall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clang -o bin/tuple main.o --std=c99 -Wpedantic -Wextra -Weverything -Wall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{42, 3.142857, &amp;#34;foobar&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, the original goal was to be able to say &lt;code&gt;tuple(42, 22./7, &amp;quot;foobar&amp;quot;)&lt;/code&gt; and be done with it.
So it&amp;rsquo;s the macro time!&lt;/p&gt;
&lt;p&gt;To solve this, we need a way to generate the array from above at preprocessor expansion time.
This is not an easy task, as the C preprocessor doesn&amp;rsquo;t have any way to iterate an arbitrary amount of arguments.
However, it&amp;rsquo;s certainly possible to iterate a &lt;em&gt;known&lt;/em&gt; amount of arguments.
So our task boils down to pre-defining &lt;em&gt;enough&lt;/em&gt; preprocessor stages to support a certain amount of arguments.
This is still a tricky task though.&lt;/p&gt;
&lt;p&gt;First, we&amp;rsquo;ll need a way to automatically detect the type of argument to set it to the &lt;code&gt;.type&lt;/code&gt; field.
This can be done either with extremely tricky and clunky use of &lt;code&gt;__builtin_types_compatible_p&lt;/code&gt; or via C11 new &lt;code&gt;_Generic&lt;/code&gt; construct.
I&amp;rsquo;ve decided to go with &lt;code&gt;_Generic&lt;/code&gt;, because it is much less code, and compile-time &lt;code&gt;if&lt;/code&gt; is not our best friend when generating code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define tuple_dispatch(x)                       \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    _Generic((x),                               \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;             char*: make_string,                \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;             double: make_double,               \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;             int: make_long,                    \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;             long: make_long)(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make_long&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;long&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make_double&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make_string&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt; *);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 4:&lt;/span&gt;
  File: &lt;code&gt;tuple.h&lt;/code&gt;
&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make_long&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;long&lt;/span&gt; x) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem){.value.i32 = x, .type = LONG};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make_double&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt; x) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem){.value.f64 = x, .type = DOUBLE};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;make_string&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt; * x) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem){.value.string = x, .type = STRING};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 5:&lt;/span&gt;
  File: &lt;code&gt;tuple.c&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;This macro will expand at &lt;strong&gt;compile&lt;/strong&gt; time to a correct helper function, creating our desired object.
Now we need to create a loop over all arguments of a variadic macro:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CONCATENATE2(arg1, arg2) arg1##arg2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_0(what, x) what(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_1(what, x, ...) what(x), FOR_EACH_0(what, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_2(what, x, ...) what(x), FOR_EACH_1(what, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_3(what, x, ...) what(x), FOR_EACH_2(what, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TUPLE_EACH_NARG_(...)                   \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    CHOOSER(__VA_ARGS__, 3, 2, 1, 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CHOOSER(_0, _1, _2, _3, N, ...)         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    N
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TUPLE_EACH_(N, what, ...) CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TUPLE_(what, ...)                                           \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    TUPLE_EACH_(TUPLE_EACH_NARG_(__VA_ARGS__), what, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 6:&lt;/span&gt;
  File: &lt;code&gt;tuple.h&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;Here, I create an iteration over four arguments at most.
It&amp;rsquo;s easy to add more, just create more &lt;code&gt;#define FOR_EACH_&amp;lt;N&amp;gt;(what, x, ...) what(x), FOR_EACH_&amp;lt;N-1&amp;gt;(what, __VA_ARGS__)&lt;/code&gt; definitions, and add respecting numbers to &lt;code&gt;TUPLE_EACH_NARG_&lt;/code&gt; and &lt;code&gt;CHOOSER&lt;/code&gt; accordingly.
This will allow us to loop in a functional style, applying a &lt;code&gt;what&lt;/code&gt; macro to each argument of a vararg macro.
Here&amp;rsquo;s how we do it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;lt;malloc.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define tuple(...)                                                          \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    __extension__({                                                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        unsigned int       size  = TUPLE_EACH_NARG_(0, __VA_ARGS__);        \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        struct TupleItem   tmp[] = {TUPLE_(tuple_dispatch, __VA_ARGS__)};   \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        struct TupleItem * arr   = malloc(sizeof(struct TupleItem) * size); \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        for (unsigned int i = 0; i &amp;lt; size; i++)                             \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;            arr[i] = tmp[i];                                                \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        (struct Tuple){.tuple = arr, .size = size};                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 7:&lt;/span&gt;
  File: &lt;code&gt;tuple.h&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;Unfortunately, this uses a statement expression extension from GCC, but luckily for me, clang supports it, and I don&amp;rsquo;t care much about MSVC.
Here, we create an array &lt;code&gt;tmp&lt;/code&gt; with the &lt;code&gt;TUPLE_&lt;/code&gt; macro, that calls &lt;code&gt;tuple_dispatch&lt;/code&gt; over every argument in &lt;code&gt;__VA_ARGS__&lt;/code&gt;.
Let&amp;rsquo;s use it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;#34;tuple.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// ------8&amp;lt;-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple tuple = tuple(42, 22./7, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pprint_tuple(&amp;amp;tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 8:&lt;/span&gt;
  File: &lt;code&gt;main.c&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;This, again gives us the same result, as before, however, reduces all boilerplate to a single &lt;code&gt;tuple&lt;/code&gt; call.
Let&amp;rsquo;s see what this expands to when we compile it with &lt;code&gt;gcc -E main.c&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple tuple = __extension__({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; size = 3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem tmp[] = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _Generic((42), &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;*: make_string, &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt;: make_double, &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt;: make_long, &lt;span style=&#34;font-weight:bold&#34;&gt;long&lt;/span&gt;: make_long)(42),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _Generic((22./7), &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;*: make_string, &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt;: make_double, &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt;: make_long, &lt;span style=&#34;font-weight:bold&#34;&gt;long&lt;/span&gt;: make_long)(22./7),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _Generic((&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;), &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;*: make_string, &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt;: make_double, &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt;: make_long, &lt;span style=&#34;font-weight:bold&#34;&gt;long&lt;/span&gt;: make_long)(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foobar&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem * arr = malloc(&lt;span style=&#34;font-weight:bold&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; TupleItem) * size);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;font-weight:bold&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; i = 0; i &amp;lt; size; i++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                arr[i] = tmp[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            (&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple){.tuple = arr, .size = size};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pprint_tuple(&amp;amp;tuple);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As I&amp;rsquo;ve mentioned, &lt;code&gt;_Generic&lt;/code&gt; will go away at compilation time and will leave invocations of respecting functions.
We&amp;rsquo;ve achieved our goal, but this solution has some problems.&lt;/p&gt;
&lt;p&gt;First, obviously &lt;code&gt;_Generic&lt;/code&gt; and &lt;code&gt;({})&lt;/code&gt; may not be available in a certain compiler, or when using an older C standard.
So the portability of this code is not very good.
Another problem is that the definitions inside the &lt;code&gt;({})&lt;/code&gt; block may shadow outer definitions.
This may not be a problem in this example, but a thing to remember.
A compiler actually will warn you about it.&lt;/p&gt;
&lt;h2 id=&#34;take-2-struct-generation&#34;&gt;Take 2 - struct generation&lt;/h2&gt;
&lt;p&gt;But then it hit me.
Why do we even need an array here?
All we really needed was this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; _0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt; _1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;* _2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define tuple(...) (struct Tuple){__VA_ARGS__}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; Tuple vaiv = tuple(42, 22./7, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{%d, %f, %s}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, vaiv._0, vaiv._1, vaiv._2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is still a tuple, &lt;em&gt;right&lt;/em&gt;?
Well, some languages have this kind of tuple access, so I think it&amp;rsquo;s OK.
Examples would be &lt;a href=&#34;https://doc.rust-lang.org/std/primitive.tuple.html&#34; target=&#34;_blank&#34;&gt;Rust&lt;/a&gt; and &lt;a href=&#34;https://ziglang.org/documentation/0.9.1/#toc-Anonymous-Struct-Literals&#34; target=&#34;_blank&#34;&gt;Zig&lt;/a&gt;.
Rust has this kind of field access, and Zig just uses anonymous structs with integer fields.
So the only challenge here is to generate such a struct.
Fortunately, the process is extremely similar:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#pragma once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TYPE_DISPATCH(X, N) X _##N;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define VALUE_DISPATCH(X, N) ._##N = (X),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define EXPAND(X) X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CONCATENATE(A, B) CONCATENATE1(A, B)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CONCATENATE1(A, B) CONCATENATE2(A, B)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CONCATENATE2(A, B) A##B
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_0(WHAT, X) WHAT(X, 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_1(WHAT, X, ...) WHAT(X, 1) FOR_EACH_0(WHAT, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_2(WHAT, X, ...) WHAT(X, 2) FOR_EACH_1(WHAT, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define FOR_EACH_3(WHAT, X, ...) WHAT(X, 3) FOR_EACH_2(WHAT, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// define more if you need more elements in the tuple
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TUPLE_EACH_NARG_(...) CHOOSER(__VA_ARGS__, 3, 2, 1, 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define CHOOSER(_0, _1, _2, _3, N, ...) N
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define REVERSE_1(X) X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define REVERSE_2(X, Y) Y, X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define REVERSE_3(X, ...) EXPAND(REVERSE_2(__VA_ARGS__)), X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define REVERSE_4(X, ...) EXPAND(REVERSE_3(__VA_ARGS__)), X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define REVERSE_(N, ...) EXPAND(REVERSE_##N(__VA_ARGS__))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define REVERSE(N, ...) REVERSE_(N, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;// also define more if you need more elements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TUPLE_EACH_(N, WHAT, ...) CONCATENATE(FOR_EACH_, N)(WHAT, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define TUPLE_(WHAT, ...) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    TUPLE_EACH_(TUPLE_EACH_NARG_(__VA_ARGS__), WHAT, __VA_ARGS__)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define tuple(...)                                                     \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    {                                                                  \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        .len = TUPLE_EACH_NARG_(_, __VA_ARGS__),                       \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        TUPLE_(VALUE_DISPATCH,                                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;               REVERSE(TUPLE_EACH_NARG_(_, __VA_ARGS__), __VA_ARGS__)) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#define deftuple(...)                                                  \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    struct {                                                           \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        int len;                                                       \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;        TUPLE_(TYPE_DISPATCH,                                          \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;               REVERSE(TUPLE_EACH_NARG_(_, __VA_ARGS__), __VA_ARGS__)) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 9:&lt;/span&gt;
  File: &lt;code&gt;tuple.h&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;ve limited the macro to support only four-element tuples, as it can be quite ridiculous with more elements than that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&amp;#34;tuple.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    deftuple(&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt;, &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;*) vaiv = tuple(42, 22./7, &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{%d, %f, %s}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, vaiv._0, vaiv._1, vaiv._2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;src-block-caption&#34;&gt;
  &lt;span class=&#34;src-block-number&#34;&gt;Code Snippet 10:&lt;/span&gt;
  File: &lt;code&gt;main.c&lt;/code&gt;
&lt;/div&gt;
&lt;p&gt;The tricky part here was to realize how to reverse the argument list.
The problem here was that our &lt;code&gt;FOR_EACH_&lt;/code&gt; macro goes forward the argument list, but backward in the sense that it starts at some arbitrary &lt;code&gt;FOR_EACH_&amp;lt;N&amp;gt;&lt;/code&gt; and continues until it reaches &lt;code&gt;FOR_EACH_0&lt;/code&gt;.
So when generating for the struct fields, I had to reverse the arguments before the generation, so the &lt;code&gt;_&amp;lt;N&amp;gt;&lt;/code&gt; fields matched.
For a better understanding, here&amp;rsquo;s the result of running only the preprocessor with &lt;code&gt;gcc -E main.c&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;struct&lt;/span&gt; { &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; len; &lt;span style=&#34;font-weight:bold&#34;&gt;char&lt;/span&gt;* _2; &lt;span style=&#34;font-weight:bold&#34;&gt;double&lt;/span&gt; _1; &lt;span style=&#34;font-weight:bold&#34;&gt;int&lt;/span&gt; _0; } vaiv = { .len = 3, ._2 = (&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;foo bar&amp;#34;&lt;/span&gt;), ._1 = (22./7), ._0 = (42), };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    printf(&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;{%d, %f, %s}&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#34;&lt;/span&gt;, vaiv._0, vaiv._1, vaiv._2);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;font-weight:bold&#34;&gt;return&lt;/span&gt; 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that while we&amp;rsquo;ve defined our tuple as &lt;code&gt;(int, double, char*)&lt;/code&gt;, the order in the struct is in reverse: &lt;code&gt;{int len; char* _2; double _1; int _0;}&lt;/code&gt;.
And because of that we now can use the initializer-list, and still access args in the correct order.
The same happens when we create the tuple itself: &lt;code&gt;tuple(42, 22./7, &amp;quot;foo bar&amp;quot;)&lt;/code&gt; becomes &lt;code&gt;{.len=3, ._2 = (&amp;quot;foo bar&amp;quot;), ._1 = (22./7), ._0 = (42),}&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So here are two ways of creating &lt;em&gt;generic&lt;/em&gt; tuples in C.
I understand that this may be not the most practical or even optimal way of creating tuples in C, but the last one is appealing to me because it&amp;rsquo;s a fully compile-time thing.
And it was a nice puzzle, especially after two years of not using C almost at all.&lt;/p&gt;
&lt;p&gt;I like the second solution more because it&amp;rsquo;s just an &lt;code&gt;tuple.h&lt;/code&gt; file, without &lt;code&gt;tuple.c&lt;/code&gt; counterpart as with the first solution.
And unlike the first solution, you don&amp;rsquo;t need to modify any code to use it, only if you need a tuple with more arguments than supported by macros, but it&amp;rsquo;s a common thing in both solutions.
There&amp;rsquo;s probably a nicer way to generate such iterations, but I&amp;rsquo;m not familiar with this one.&lt;/p&gt;
&lt;p&gt;Though, unlike the first implementation, the second one doesn&amp;rsquo;t allow iteration over the tuple in any form, as it&amp;rsquo;s not really a sequence anymore, so the &lt;code&gt;len&lt;/code&gt; field may be a bit pointless.
In statically typed languages iteration over a tuple can be hard, because each element can have a different type.
It was possible with the first implementation because we&amp;rsquo;ve explicitly stored tuple item type in the tuple item itself, so we had to implement &amp;ldquo;generic&amp;rdquo; functions that would know how to work with a given element, but the dispatch happened at runtime.
Rust, for example, doesn&amp;rsquo;t allow iteration over tuples, as it doesn&amp;rsquo;t even guarantee the order of elements in the tuple.
&lt;a href=&#34;https://ziglang.org/&#34; target=&#34;_blank&#34;&gt;Zig&lt;/a&gt; allows iteration, but only at compile-time, as far as I understand it.&lt;/p&gt;
&lt;p&gt;Speaking of Zig, right now I&amp;rsquo;m learning it, and it actually brings me a lot of memories about learning C, and overall feels great.
In this blog, I&amp;rsquo;ve &lt;a href=&#34;https://andreyor.st/posts/2020-04-06-c-needs-a-better-syntax/&#34;&gt;already ranted about C&lt;/a&gt; mostly its macros and syntax, and I still think most things I&amp;rsquo;ve said are valid.
E.g. the tuple macro above suffers from the requirement to &lt;code&gt;typedef&lt;/code&gt; compound types, like structs or &lt;code&gt;long type&lt;/code&gt; things.&lt;/p&gt;
&lt;p&gt;And learning Zig now feels like learning a better C.
A lot of patterns are probably doable in both languages, given how minimalist both of those are, but Zig almost always feels much clearer.&lt;/p&gt;
&lt;p&gt;Consider an amateur attempt at creating &lt;code&gt;Cons&lt;/code&gt; cells in Zig, and then doing mostly the same thing in C via macros:&lt;/p&gt;
&lt;figure class=&#34;invertable&#34;&gt;&lt;img src=&#34;https://andreyor.st/2022-03-15-generic-tuples-in-c/zig_vs_c.jpg&#34;
         alt=&#34;Figure 1: C on the left, Zig on the right&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;&lt;span class=&#34;figure-number&#34;&gt;Figure 1: &lt;/span&gt;C on the left, Zig on the right&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;(Posted it as an image, because this post already has way too much code. I&amp;rsquo;ve described how this kind of generics works in &lt;a href=&#34;https://andreyor.st/posts/2020-04-06-c-needs-a-better-syntax/#macros&#34;&gt;Macros section&lt;/a&gt; of the already mentioned C rant.)&lt;/p&gt;
&lt;p&gt;Well, this is another approach to generic functions in C, and it&amp;rsquo;s not that hard to write such macros - just write it as an ordinary code, then select a type you need to be generic and make a few text substitutions with your editor of choice.
But while this is doable, and &lt;em&gt;works&lt;/em&gt;, my main point is that  Zig feels a lot more clear, and achieves the same thing, I believe via mostly the same ways.
Being more clear is an obvious benefit, and C code here has a nasty bug, kudos if you&amp;rsquo;ll manage to spot it in this macro mess.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m bringing Zig here, not because it has support for tuples or a more clear syntax but because even though C gets new standards, it still feels like it&amp;rsquo;s standing in place, and nothing really changes over the years.
And Zig, while young, has quite ambitious goals of both supporting C ABI and &lt;a href=&#34;https://ziglang.org/learn/overview/#zig-competes-with-c-instead-of-depending-on-it&#34; target=&#34;_blank&#34;&gt;competing with C without depending on it&lt;/a&gt;.
If you write in C, I encourage you to go and try Zig for a bit - it has a clear vision of a small system language.
Another interesting thing on the horizon is &lt;a href=&#34;https://drewdevault.com/2022/03/13/Why-am-I-working-in-private.html&#34; target=&#34;_blank&#34;&gt;Drew DeVault&amp;rsquo;s secret system language&lt;/a&gt;.
I have not yet looked at it, but from what I&amp;rsquo;ve read in the blog posts, it seems quite interesting.
We&amp;rsquo;ll see how it compares to Zig when it&amp;rsquo;ll becomes available.&lt;/p&gt;
&lt;p&gt;Going back to the main topic of this post, I think there are more robust ways of doing this.
Probably a lot of dynamically typed languages that are implemented in C are doing something like that, mainly for implementing a generic type to pass around.
I&amp;rsquo;m yet to try my solution in practice, and as I&amp;rsquo;ve mentioned, this probably won&amp;rsquo;t work in its current state.
But I hope it was at least an example of interesting use of C macros.
And now, in case I&amp;rsquo;ll forget how to do this macro iteration, I&amp;rsquo;ll have a place to look :)&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: Generic* tuples in C&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 15 Mar 2022 21:03:00 +0300</pubDate>
    </item><item>
      <title>New look</title>
      <link>https://andreyor.st/posts/2022-02-22-new-look/</link>
      <guid>https://andreyor.st/posts/2022-02-22-new-look/</guid>
      <description>&lt;p&gt;About a year ago I&amp;rsquo;ve started thinking about changing the theme of the blog and hopefully designing my own theme.
This didn&amp;rsquo;t go so well, as I had very little free time to actually sit and do the thing.
So at the end of the last year, I decided that I&amp;rsquo;ll prioritize this task at the start of 2022, as usually there&amp;rsquo;s not so much stuff to do at the year&amp;rsquo;s start, rather than mid-year.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://andreyor.st/posts/2021-12-30-recap/#plans-for-2022&#34;&gt;Initially&lt;/a&gt;, I&amp;rsquo;ve decided to move away from Hugo to a pure Org Mode-based static site generation via &lt;a href=&#34;https://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html&#34; target=&#34;_blank&#34;&gt;Org Publish&lt;/a&gt;.
Not that Hugo doesn&amp;rsquo;t work, or has problems, I just wanted to try out something new.
So I&amp;rsquo;ve created a new blog, where I&amp;rsquo;ve started experimenting, using my old posts, and the new publishing system.
It didn&amp;rsquo;t work out, unfortunately.&lt;/p&gt;
&lt;p&gt;There were two main problems I encountered.
The first one was that I was unsure how to properly organize pages.
What I&amp;rsquo;m talking about specifically is that when you&amp;rsquo;re reading a post in my blog, you usually see the &lt;code&gt;blogname.domain/posts/post_name/&lt;/code&gt; in the address bar.
However, pages generated with Org Publish were &lt;code&gt;blogname.domain/posts/post_name/index.html&lt;/code&gt;, and I couldn&amp;rsquo;t figure out how to make an automatic redirection, or edit links to automatically omit the &lt;code&gt;index.html&lt;/code&gt; part.
I&amp;rsquo;ve tried patching the code of Org Publish, but couldn&amp;rsquo;t figure out where the link transformation happens.
Of course, I could just use &lt;code&gt;blogname.domain/posts/post_name.html&lt;/code&gt; format, but this would break all links referring to my posts in other blogs or social media.
And for now, I&amp;rsquo;d like to avoid that.&lt;/p&gt;
&lt;p&gt;Another problem was with generating RSS feeds.
Hugo does a great job creating separate feeds for every category and tag, so readers can subscribe only to the topic they&amp;rsquo;re interested in.
Same with blog aggregators - no need to filter posts via some regular expressions, just specify the correct feed URL.
Org Publish can&amp;rsquo;t create RSS by itself, you need a separate package, called &lt;code&gt;ox-rss&lt;/code&gt; for that.
It was a bit hard to install, given that Org Mode removed the contrib packages to a &lt;a href=&#34;https://git.sr.ht/~bzg/org-contrib&#34; target=&#34;_blank&#34;&gt;separate repository&lt;/a&gt;, and unfortunately, &lt;code&gt;ox-rss&lt;/code&gt; doesn&amp;rsquo;t seem capable of creating feeds similarly to how Hugo does it.&lt;/p&gt;
&lt;p&gt;So ultimately I&amp;rsquo;ve decided to stay with Hugo for the time being, and, for now, simply change a theme.
I&amp;rsquo;ve changed themes before, but that was mainly due to the fact that I came to dislike a certain theme, and wanted something different.
Especially since (I believe) I&amp;rsquo;m the one who sees my blog the most, it&amp;rsquo;s important for me to have something I like looking at.
Originally, I started this blog with the &lt;a href=&#34;https://github.com/vividvilla/ezhil&#34; target=&#34;_blank&#34;&gt;Ezhil&lt;/a&gt; theme, but a month after that I replaced it with a more &lt;em&gt;cool-looking&lt;/em&gt; &lt;a href=&#34;https://github.com/spf13/hyde&#34; target=&#34;_blank&#34;&gt;Hyde&lt;/a&gt; theme with its thick black bar on the left and bold fonts.
But around April 5th of 2020, I moved to &lt;a href=&#34;https://github.com/qqhann/hugo-primer&#34; target=&#34;_blank&#34;&gt;Hugo Primer&lt;/a&gt;, and tweaked it ever since, changing colors and templates.&lt;/p&gt;
&lt;p&gt;It was a good theme, but it was still a bit too busy for my liking.
It is designed to be visually similar to how GitHub looks, so it had a lot of small widgets, like circled numbers, tags were little rectangles that resemble badges found in most repositories, and so on.
Overall the experience was solid, but one thing I disliked, in particular, was that there was an &lt;a href=&#34;https://github.com/qqhann/hugo-primer/blob/cc0117edbb279310cfbfdda3b9e420941f73d131/static/assets/primer-build.css&#34; target=&#34;_blank&#34;&gt;enormous CSS file&lt;/a&gt;, with 8k lines when un-minified.
This made it harder to tweak the styling of the blog and obviously increased page load time a bit.&lt;/p&gt;
&lt;p&gt;So I went to the &lt;a href=&#34;https://themes.gohugo.io/&#34; target=&#34;_blank&#34;&gt;Hugo themes page&lt;/a&gt; and searched for a nice and minimal theme that can work as a base.
After quite a bit of searching, I&amp;rsquo;ve found several candidates: &lt;a href=&#34;https://github.com/Mitrichius/hugo-theme-anubis&#34; target=&#34;_blank&#34;&gt;Anubis&lt;/a&gt;, &lt;a href=&#34;https://github.com/athul/archie&#34; target=&#34;_blank&#34;&gt;Archie&lt;/a&gt;, &lt;a href=&#34;https://github.com/mavidser/hugo-rocinante&#34; target=&#34;_blank&#34;&gt;Rocinante&lt;/a&gt;, and &lt;a href=&#34;https://github.com/yihui/hugo-xmin&#34; target=&#34;_blank&#34;&gt;XMin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anubis was my first candidate, but I ended up dropping it.
It does feature automatic change to the dark version, which happens synchronously with the change of system theme, which is a nice touch.
But it also has some JavaScript, and I&amp;rsquo;d wanted to avoid it unless really necessary for a certain article to work.
And with the dark mode came some problems, as the inline code snippets remained in their original color, thus being very bright.
I could change that, but there were other variants to check before that.&lt;/p&gt;
&lt;p&gt;The Archie theme didn&amp;rsquo;t work for me - it was too contrasting, and it also has JS.
Overall, the Network page looked pretty busy for loading such a simple-looking theme.&lt;/p&gt;
&lt;p&gt;XMin was very nice and minimal, I&amp;rsquo;ve considered it as a way to go for a while.
However, after browsing different pages with it I&amp;rsquo;ve noticed some eye strain, perhaps due to the contrast, and relatively small fonts.
Not that this can&amp;rsquo;t be tweaked, but I had one more theme to try.&lt;/p&gt;
&lt;p&gt;Rocinante was a weird one.
At first, I didn&amp;rsquo;t like it, but then I decided to try and tweak it.
And after some very small tweaks here and there, I&amp;rsquo;ve got what you&amp;rsquo;re looking at right now.
I&amp;rsquo;ve kept the custom color I&amp;rsquo;ve used in my previous theme variant, removed some of the visual noise introduced by additional colors and separators, moved some elements around, and that&amp;rsquo;s it!
I really like the result, and it&amp;rsquo;s very light as well.
And now, that it&amp;rsquo;s not a huge minified CSS I&amp;rsquo;m working with, I can finally tweak things as I need, so maybe some changes will pop from time to time.
I&amp;rsquo;ve also added a dark variant that is automatically selected via CSS &lt;code&gt;@media(prefers-color-scheme: light|dark)&lt;/code&gt; &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries&#34; target=&#34;_blank&#34;&gt;media query&lt;/a&gt;, but it may need some tweaking.
So Feel free to tell me if you like the new look, or preferred the old variant!&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t be releasing these tweaks as a standalone theme, as with those my blog has more chances of being a bit more individual.
But nothing prevents you from grabbing the CSS and tweaking the theme&amp;rsquo;s templates a bit to achieve a similar look if you want.&lt;/p&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: New look&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Tue, 22 Feb 2022 18:58:00 +0300</pubDate>
    </item><item>
      <title>What if structural editing was a mistake?</title>
      <link>https://andreyor.st/posts/2022-02-20-what-if-structural-editing-was-a-mistake/</link>
      <guid>https://andreyor.st/posts/2022-02-20-what-if-structural-editing-was-a-mistake/</guid>
      <description>&lt;p&gt;Not so long ago I&amp;rsquo;ve written about &lt;a href=&#34;https://dawranliou.com/blog/structural-editing-in-vanilla-emacs/&#34; target=&#34;_blank&#34;&gt;Paredit and its quirks&lt;/a&gt;.
I&amp;rsquo;ve been happily using Smartparens ever since that post, but something still bugged me.
I was constantly thinking about the fact that Smartparens has numerous quirks in various languages and some known bugs that are unlikely to be fixed in the foreseeable future, given that the main maintainer doesn&amp;rsquo;t have a lot of spare time.
And I&amp;rsquo;m not blaming it, maintaining open-source projects is a hard task, and unfortunately, I can&amp;rsquo;t fix most of the bugs, because I&amp;rsquo;m not as familiar with the code-base.
So I went searching for new installments in the structural editing space.
I already knew about Parinfer, and unfortunately, it&amp;rsquo;s not that great to use in a team, as it generates a lot of small formatting changes upon opening the file, which results in a lot of noise in Git afterward.
What I was mainly interested in is parser-based structural editing &amp;ndash; something like what Smartparens does, but with an actual parser, like &lt;a href=&#34;https://tree-sitter.github.io/tree-sitter/&#34; target=&#34;_blank&#34;&gt;Tree Sitter&lt;/a&gt;.
There were a few packages for emacs, namely &lt;a href=&#34;https://github.com/ethan-leba/tree-edit&#34; target=&#34;_blank&#34;&gt;tree-edit&lt;/a&gt; and &lt;a href=&#34;https://github.com/mickeynp/combobulate&#34; target=&#34;_blank&#34;&gt;combobulate&lt;/a&gt; but the language selection that they support is very poor.
Having structural editing in Python is cool I guess, but I don&amp;rsquo;t write in Python, and since the languages I use are not yet supported, these packages are not an option, at least for me.&lt;/p&gt;
&lt;p&gt;And shortly after that, I found a nice post about &lt;a href=&#34;https://dawranliou.com/blog/structural-editing-in-vanilla-emacs/&#34; target=&#34;_blank&#34;&gt;structural editing in vanilla Emacs&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
This post describes how one can achieve some facilities of structural editing in Emacs without using Paredit or Smartparens, or any external packages for that matter.
In another post in that blog, a particularly interesting &lt;a href=&#34;https://old.reddit.com/r/emacs/comments/l7khmk/what_key_binding_scheme_do_you_use_to_handle/gl9fcqs/&#34; target=&#34;_blank&#34;&gt;Reddit thread&lt;/a&gt; is mentioned, which has some opinions about strict paren checking that Paredit and Smartparens introduce.&lt;/p&gt;
&lt;p&gt;Which got me thinking - maybe structural editing really isn&amp;rsquo;t something I should pursue.
The title says &amp;ldquo;mistake&amp;rdquo; but it&amp;rsquo;s obviously clickbait.
I don&amp;rsquo;t think that structural editing is a mistake, it&amp;rsquo;s a pretty useful tool with its set of compromises.
Parser-based structure editing can lift some of the compromises and fix some bugs, but some languages may not be supported, or have partial support, which comes with a set of downsides on its own.
I mostly want this for Lisps, and Emacs is already pretty good at inferring the structure of the Lisp code, so for such languages parser probably would be overkill, but still, I&amp;rsquo;d like to have everything structure related in a single package, if possible.
On the other hand, thinking about it right now, there are not that many features I need from a structural editing package, that I can&amp;rsquo;t do by hand or automate.
So maybe I just value those too much?&lt;/p&gt;
&lt;p&gt;With that in mind, I&amp;rsquo;ve decided to try living some time without any structural editing package, only relying on what&amp;rsquo;s available in Emacs or what I&amp;rsquo;ve written myself.
I&amp;rsquo;m feeling pretty confident in using structural editing by now - I often slurp, splice, and convolute expressions without thinking about what I need to do, it just comes off my fingertips.
Taking this away will mess with my muscle memory a lot, and I&amp;rsquo;ll probably become less efficient, but maybe I&amp;rsquo;ll learn something new.&lt;/p&gt;
&lt;p&gt;This post will be about the experience I had during this experiment.
I&amp;rsquo;ve written this over time, and different sections were written pretty much right after I felt some difference.&lt;/p&gt;
&lt;h2 id=&#34;initial-struggle&#34;&gt;Initial struggle&lt;/h2&gt;
&lt;p&gt;After disabling Smartparens I&amp;rsquo;ve quickly understood all that pain of writing in Lisp without automatic parenthesis insertion and balance checking.
I&amp;rsquo;ve never seen balance-related errors for some years since I&amp;rsquo;ve pretty much always used something that tried its best at keeping parentheses balanced.
But now, since no such thing is enabled, I&amp;rsquo;ve started getting these whether I just evaluate an expression, or try to compile a file.
So the first thing I did was add a &lt;code&gt;local-write-file-hooks&lt;/code&gt; to check parentheses:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;font-weight:bold;font-style:italic&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup-before-save-hooks&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;local-write-file-hooks&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;check-parens&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-style:italic&#34;&gt;&amp;#39;common-lisp-modes-mode-hook&lt;/span&gt; &lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#666;font-weight:bold;font-style:italic&#34;&gt;setup-before-save-hooks&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this hook, I can at least immediately get a warning that I&amp;rsquo;ve messed up.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;common-lisp-modes-mode&lt;/code&gt; is a package I&amp;rsquo;ve &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/05b72a3197fec2c8b7875c4ad0fc02d06fc668c7/.config/emacs/init.el#L137-167&#34; target=&#34;_blank&#34;&gt;created in my init file&lt;/a&gt; to enable common things across all Lisps.
Such things included structural editing, automatic indentation on typing, and so forth.
Most of these things are now disabled, but the mode is still quite useful, as can be seen above.&lt;/p&gt;
&lt;p&gt;Another thing that bothered me enough is that now that I don&amp;rsquo;t have Smartparens bindings, I&amp;rsquo;ve lost some pretty handy things, such as, well, slurping and sexp convoluting.
Though slurping and barfing are &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/05b72a3197fec2c8b7875c4ad0fc02d06fc668c7/.config/emacs/init.el#L241-281&#34; target=&#34;_blank&#34;&gt;easy enough to implement&lt;/a&gt;, or even do by hand.&lt;/p&gt;
&lt;p&gt;And another small annoyance is that since I don&amp;rsquo;t use transient mark mode&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, I now have to use numerical prefix argument in even more cases.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wrapping the next expression in parentheses:
&lt;ul&gt;
&lt;li&gt;Smartparens: &lt;kbd&gt;M-(&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Vanilla, &lt;code&gt;transient-mark-mode&lt;/code&gt; on: &lt;kbd&gt;C-M-SPC&lt;/kbd&gt;, &lt;kbd&gt;M-(&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Vanilla, &lt;code&gt;transient-mark-mode&lt;/code&gt; off: &lt;kbd&gt;M-1&lt;/kbd&gt;, &lt;kbd&gt;M-(&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Raising S-expression and all following expressions:
&lt;ul&gt;
&lt;li&gt;Smartparens: &lt;kbd&gt;M-&amp;lt;up&amp;gt;&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Vanilla, &lt;code&gt;transient-mark-mode&lt;/code&gt; on: repeat &lt;kbd&gt;C-M-SPC&lt;/kbd&gt; till the last, &lt;kbd&gt;M-x raise-sexp RET&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Vanilla, &lt;code&gt;transient-mark-mode&lt;/code&gt; off: count expressions by hand, &lt;kbd&gt;M-&amp;lt;N&amp;gt;&lt;/kbd&gt; where &lt;code&gt;&amp;lt;N&amp;gt;&lt;/code&gt; is the number of expressions, &lt;kbd&gt;M-x raise-sexp RET&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Killing til the end of the expression:
&lt;ul&gt;
&lt;li&gt;Smartparens: &lt;kbd&gt;C-k&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Vanilla, &lt;code&gt;transient-mark-mode&lt;/code&gt; on: repeat &lt;kbd&gt;C-M-SPC&lt;/kbd&gt; till the last, &lt;kbd&gt;C-w&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Vanilla, &lt;code&gt;transient-mark-mode&lt;/code&gt; off: count expressions, &lt;kbd&gt;M-&amp;lt;N&amp;gt;&lt;/kbd&gt;, &lt;kbd&gt;C-M-k&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As can be seen, some quality of life improvements are definitively lost.
This is of course because, without any guarantee that the input is balanced, it&amp;rsquo;s hard to automate things.
In strict mode, Smartparens takes a great deal of keeping expressions balanced, so things like killing til the end of sexp always work as expected.
Without strict mode, we need to manually count or select the needed amount before pressing &lt;kbd&gt;C-M-k&lt;/kbd&gt;.
I&amp;rsquo;m kinda OK with that, but it&amp;rsquo;s still a bit tricky to do for me.&lt;/p&gt;
&lt;h2 id=&#34;adoption-period&#34;&gt;Adoption period&lt;/h2&gt;
&lt;p&gt;After some time I&amp;rsquo;ve noticed that I&amp;rsquo;m no longer fighting my habits, and unbalanced code is not as an issue as it initially was.
I&amp;rsquo;ve definitively started using more numerical arguments.
But some things I still had to implement.&lt;/p&gt;
&lt;p&gt;One of such things was a &lt;a href=&#34;https://gitlab.com/andreyorst/dotfiles/-/blob/05b72a3197fec2c8b7875c4ad0fc02d06fc668c7/.config/emacs/init.el#L282-314&#34; target=&#34;_blank&#34;&gt;function like &lt;code&gt;sp-rewrap-sexp&lt;/code&gt;&lt;/a&gt;.
I&amp;rsquo;ve mapped it to &lt;kbd&gt;M-r&lt;/kbd&gt;.
With this function it&amp;rsquo;s possible to quickly wrap something like &lt;code&gt;█foo bar&lt;/code&gt; (&lt;code&gt;█&lt;/code&gt; is a point) in any kind of delimiters with &lt;kbd&gt;M-2 M-( M-r [&lt;/kbd&gt; producing &lt;code&gt;[foo bar]&lt;/code&gt;.
And it automatically escapes strings, so something like &lt;code&gt;█foo &amp;quot;bar&amp;quot; baz&lt;/code&gt; with the following chords &lt;kbd&gt;M-3 M-( M-r &amp;ldquo;&lt;/kbd&gt; becomes &lt;code&gt;█&amp;quot;foo \&amp;quot;bar\&amp;quot; baz&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Slurping and barfing doesn&amp;rsquo;t seem to go away any time soon, but I&amp;rsquo;ve actually never found any use cases for backward versions of these commands.
Maybe that&amp;rsquo;s because of the prefix nature of Lisps, and arguments are more often appended to the list rather than prepended.
So there are no such variants in my small &lt;code&gt;structural-mode&lt;/code&gt; package.&lt;/p&gt;
&lt;h2 id=&#34;thoughts-on-structural-editing-in-general&#34;&gt;Thoughts on structural editing in general&lt;/h2&gt;
&lt;p&gt;I think a lot of people were misguided by Paredit&amp;rsquo;s notion of structural editing.
Think of it like that - most such packages infer the structure from the code, not the other way around.
Well, Lisps are naturally good at this, because all you need to do to map code to its structure is to make parentheses always stay balanced.
This doesn&amp;rsquo;t work for other languages, as their structure almost always has nothing to do with their syntax.
So a structural editor for, say, Python, shouldn&amp;rsquo;t be built on top of non-structural, syntax-inferred information to begin with.&lt;/p&gt;
&lt;p&gt;My point is, that we need a way to infer the structure from existing code only once, and then work only with it, not with the code.
But right now, most attempts at structural editing packages that integrate with an editor are based on the idea of constant inference of structure, either via an external parser or very smart use of regular expressions, and custom parser around those.
Again, given that Lisps are written directly with the data structure they operate on, you can pretty much infer the structure on every keystroke, the only requirement is for the parentheses to be balanced, but this will not work for other languages as smoothly.
And projects like Tree-Sitter can close the gap, but are not a solution for the problem, because it is still inference.&lt;/p&gt;
&lt;p&gt;I know some projects that implemented the idea in a more close way to what I&amp;rsquo;m talking about in the first sentence of the previous paragraph.
One such example is &lt;a href=&#34;https://vlojure.io/&#34; target=&#34;_blank&#34;&gt;Vlojure&lt;/a&gt;.
Note that there&amp;rsquo;s no actual code, only its structure, represented as circles.
Given that you can freely move these circles around, copy those, descend into, and do other stuff makes it a real structure-based editor.
Underneath, the code is generated from these structures, and such code can be stored in a file, and inferred back to this form.
But working with circles alone may be a bit hard.
So people have made hybrid editors, that still use code as a basis, but put it into structural blocks that can be arbitrarily composed.
However, to my knowledge, no such system had any significant spread, and the only one that may be considered an example of success is &lt;a href=&#34;https://scratch.mit.edu/&#34; target=&#34;_blank&#34;&gt;Scratch&lt;/a&gt;.
Yes, I consider Scratch&amp;rsquo;s IDE as a structural editor, because you can manipulate code structure directly.
Of course, there are more structural editors out there, but I think these are considered experiments.&lt;/p&gt;
&lt;p&gt;And such editors come with one obvious downside, which is they&amp;rsquo;re limited and require specific tooling.
By specific tooling, I mean things like diffing, code searching, e.t.c. - all that needs to be built separately for a specific structure implementation that the editor uses.
And, as a result, they give you a certain workflow you must obey, because there are no other ways of doing things in such editors.&lt;/p&gt;
&lt;p&gt;This is similar to the strictness that Paredit and Smartparens rely on to provide their features, and perhaps that&amp;rsquo;s why a lot of people consider Paredit a package for structural editing.
Making other languages&amp;rsquo; syntax strict is quite hard, so error-tolerant parsers like Tree-Sitter will work, but at the moment when the structure is broken there&amp;rsquo;s no guarantee of correctness, and that&amp;rsquo;s a problem.
So maybe structural editing was a mistake?&lt;/p&gt;
&lt;p&gt;Certainly not, and when it works - it really works.
Emacs has a lot of inbuilt stuff for structure-based navigation with its &lt;code&gt;thingatpt&lt;/code&gt; package, so it would be a waste not to use it, and things like Paredit exist for a reason.
And sometimes, leveraging language-specific tooling can work pretty well, as demonstrated by &lt;a href=&#34;https://gitlab.com/gopiandcode/gopcaml-mode&#34; target=&#34;_blank&#34;&gt;this package for OCaml&lt;/a&gt;.
Parinfer is another beast here.
It is Lisp-exclusive structure inference taken to the next level, as it does both inferences and maintains strictness at the same time.
I, actually, think that Parinfer is the best structural editing package for Lisps because it&amp;rsquo;s both transparent and doesn&amp;rsquo;t require strict balance, although it does require correct indentation.
And, you can use all structure-based edits like slurping and barfing with it with no problem.
So this idea as a whole still needs exploration, in my opinion.&lt;/p&gt;
&lt;p&gt;Ideally, I&amp;rsquo;d like a less buggy and a more robust version of Smartparens, but it worked pretty fine for my use-cases, and for a lot of other people, so by all means use what works best for you.
That&amp;rsquo;s all I have on this topic, but maybe I&amp;rsquo;ll return to it in the future once I make a decision on whether to give Smartparens or Paredit another go.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I guess we&amp;rsquo;ve come a full circle :)&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;You can use both methods despite the fact if &lt;code&gt;transient-mark-mode&lt;/code&gt; is enabled or not, though, you may need to temporarily enable it with &lt;kbd&gt;C-SPC C-SPC&lt;/kbd&gt; if it&amp;rsquo;s disabled.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&#34;comment-link&#34;&gt; &lt;a href=&#34;mailto:%61%6e%64%72%65%79%6f%72%73%74%2b%62%6c%6f%67%40%67%6d%61%69%6c%2e%63%6f%6d?subject=Comment: What if structural editing was a mistake?&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Comment via email&lt;/a&gt;&lt;/div&gt;</description>
      <pubDate>Sun, 20 Feb 2022 22:04:00 +0300</pubDate>
    </item><item>
      <title>Lua appreciation post</title>
      <link>https://andreyor.st/posts/2022-02-13-lua-appreciation-post/</link>
      <guid>https://andreyor.st/posts/2022-02-13-lua-appreciation-post/</guid>
      <description>&lt;p&gt;Lua is one of the most pleasant languages that I’ve used so far.
Well, I’m not writing in Lua directly, instead, I use  &lt;a href=&#34;https://fennel-lang.org/&#34; target=&#34;_blank&#34;&gt;Fennel&lt;/a&gt; - a compiler for a Clojure/Lisp-like syntax to Lua.
Because of that, I actually don’t really know Lua syntax that well, even though it’s really simple, it still has some quirks.
That’s something I like about hosted languages and transpilers - you may leverage the power of a good runtime while sticking to the syntax you know well.
But I’ll do my best here, describing things I love about Lua and its runtime, and some things that I wish have been a bit better.&lt;/p&gt;
&lt;h2 id=&#34;the-runtime&#34;&gt;The runtime&lt;/h2&gt;
&lt;p&gt;And the first thing I&amp;rsquo;d like to talk about is how great the Lua runtime actually is!
Lua is small, its runtime is lightweight, and has good enough performance to use in a variety of places.
It can be used from &lt;a href=&#34;https://love2d.org/&#34; target=&#34;_blank&#34;&gt;games&lt;/a&gt; to &lt;a href=&#34;https://awesomewm.org/&#34; target=&#34;_blank&#34;&gt;window managers&lt;/a&gt; and text editors, such as &lt;a href=&#34;https://neovim.io/&#34; target=&#34;_blank&#34;&gt;NeoVim&lt;/a&gt;, &lt;a href=&#34;https://micro-editor.github.io/&#34; target=&#34;_blank&#34;&gt;Micro&lt;/a&gt;, &lt;a href=&#34;https://github.com/martanne/vis&#34; target=&#34;_blank&#34;&gt;Vis&lt;/a&gt;, which all provide a way to use Lua for configuration and scripting.
There even is an editor that is almost fully implemented in Lua, called &lt;a href=&#34;https://github.com/rxi/lite&#34; target=&#34;_blank&#34;&gt;Lite&lt;/a&gt;, and it can be extended via it as well.
This is because Lua is actually pretty suited for embedding in applications and even can be used on some micro-controllers too, so it is quite versatile!&lt;/p&gt;
&lt;p&gt;What I like the most is perhaps how expressive you can be even with so little the runtime gives you.
Being very small, Lua supports first-class functions, closures, tail call optimization, collaborative multitasking via coroutines, and more!
To be frank it often &lt;a href=&#34;https://www.lua.org/doc/hopl.pdf&#34; target=&#34;_blank&#34;&gt;feels like&lt;/a&gt; you&amp;rsquo;re using Scheme with a different syntax (which is actually can be fixed with Fennel).
All these features already make Lua very expressive and powerful, but Lua actually has more things to offer!&lt;/p&gt;
&lt;h2 id=&#34;the-standard-library&#34;&gt;The standard library&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s often said that Lua has no standard library, but I don&amp;rsquo;t think it&amp;rsquo;s practically true.
Lua, for sure, has a small standard library, but it&amp;rsquo;s really surprising how far you can get away with just it!&lt;/p&gt;
&lt;p&gt;By default, Lua features these modules: &lt;code&gt;io&lt;/code&gt;, &lt;code&gt;os&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;utf8&lt;/code&gt;, &lt;code&gt;math&lt;/code&gt;, &lt;code&gt;coroutine&lt;/code&gt;, &lt;code&gt;table&lt;/code&gt;, &lt;code&gt;package&lt;/code&gt;, &lt;code&gt;debug&lt;/code&gt;.
Not all of these modules are present at all times though.
For example, it&amp;rsquo;s a common thing to remove the &lt;code&gt;debug&lt;/code&gt; module from production systems for better sandboxing.
Some systems restrict or even remove the &lt;code&gt;package&lt;/code&gt; module, so custom package searchers could not be added.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s still much smaller than in other languages, like Python, which Lua is often compared to, but even with all of that that is available, it&amp;rsquo;s possible to build exciting stuff!
For example, Fennel itself is built entirely in Lua, without any other third-party library.
As a result, Fennel is a single Lua script, which can be executed as a standalone language, or used to do ahead-of-time compilation from Fennel to Lua (and &lt;a href=&#34;https://fennel-lang.org/see&#34; target=&#34;_blank&#34;&gt;back!&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The standard library is minimalist, for so to speak.
For example, there are no multitasking facilities, as one might expect from a modern language, only basic coroutines.
But given the embeddable nature of Lua, this is a good thing, because not all systems have support for real multitasking, or you might need more specific facilities for your particular needs.
Coroutines allow you to implement what suits your needs best.&lt;/p&gt;
&lt;p&gt;But one of the most powerful things in Lua is tables.&lt;/p&gt;
&lt;h2 id=&#34;tables&#34;&gt;Tables&lt;/h2&gt;
&lt;p&gt;The main data structure in Lua is a table.
A table in Lua is a compound type, containing both sequential and associative parts together in one table.
Originally there was only the associative part, but the sequential part was later added for better performance.
There are no other data structures in Lua, e.g. no linked lists, no tries, no sets.
Furthermore, Lua doesn&amp;rsquo;t have classes!&lt;/p&gt;
&lt;p&gt;So you might wonder how&amp;rsquo;s tables are the most powerful features of Lua?
The answer is simple - a table can be &lt;em&gt;any&lt;/em&gt; of that!
And Lua provides us with a lot of ways to achieve that.&lt;/p&gt;
&lt;p&gt;This is possible because in Lua tables are flexible.
Not only tables can contain any other type, like strings, functions, or other tables, it&amp;rsquo;s behavior can be altered via &lt;a href=&#34;http://www.lua.org/manual/5.3/manual.html#2.4&#34; target=&#34;_blank&#34;&gt;metatables&lt;/a&gt;.
So implementing a class is a matter of implementing a proper set of metamethods, using a table as a container.
For example, &lt;a href=&#34;https://github.com/andreyorst/lazy-seq&#34; target=&#34;_blank&#34;&gt;lazy evaluated linked lists&lt;/a&gt; are entirely possible by using a combination of closures and metatables.
&lt;a href=&#34;https://github.com/andreyorst/itable&#34; target=&#34;_blank&#34;&gt;Immutable tables&lt;/a&gt; are possible, thanks to inbuilt &lt;code&gt;__index&lt;/code&gt; and &lt;code&gt;__newindex&lt;/code&gt; metamethods.
And because tables can be thrown as errors, and because tables are dynamic, it&amp;rsquo;s possible to implement a different error handling system, like a &lt;a href=&#34;https://github.com/andreyorst/fennel-conditions&#34; target=&#34;_blank&#34;&gt;condition system&lt;/a&gt; from Common Lisp.&lt;/p&gt;
&lt;p&gt;Not only that, but Lua provides a &lt;code&gt;table&lt;/code&gt; module in its standard library, which provides various functions for working with tables.
It contains only necessary stuff, and more complex things can be built on top of it.&lt;/p&gt;
&lt;p&gt;Another neat thing about tables is that Lua has a really clear vision of iterators.
Lua provides two main functions for table iteration: &lt;code&gt;pairs&lt;/code&gt; and &lt;code&gt;ipairs&lt;/code&gt;.
Their main difference is that &lt;code&gt;ipairs&lt;/code&gt; only traverses the sequential part of the table, and &lt;code&gt;pairs&lt;/code&gt; traverses table as a whole.
And these iterators are just pure functions, that you (theoretically) can share, as there&amp;rsquo;s no inner state.
And because iterators are lazy, it&amp;rsquo;s not a problem to consume really big resources, such as tables or even files.&lt;/p&gt;
&lt;p&gt;All in all, tables are a very flexible part of Lua, which allows the user to implement anything, given enough time and determination of course.&lt;/p&gt;
&lt;h2 id=&#34;problems&#34;&gt;Problems&lt;/h2&gt;
&lt;p&gt;But not that there aren&amp;rsquo;t any problems in Lua - there are, as in everything.
The first one is that the lack of some things in the standard library often shows when you want to create a script that you can later distribute to other people as an executable.
This can be solved by embedding the library code into your application via the &lt;code&gt;package&lt;/code&gt; module, and Fennel actually does it, so this can be migrated.&lt;/p&gt;
&lt;p&gt;But this raises another problem - the language ecosystem.
Lua has a de facto package manager, called &lt;a href=&#34;https://luarocks.org/&#34; target=&#34;_blank&#34;&gt;LuaRocks&lt;/a&gt;, and while Lua definitively rocks, LuaRocks doesn&amp;rsquo;t (IMO).
I mean, it does its job, but it is extremely clunky, and not very user-friendly.
Lua actually contributed to this problem, because it has changed its notion of modules during some releases, and also because it doesn&amp;rsquo;t have proper support for relative &lt;code&gt;require&lt;/code&gt;.
As a result, a lot of libraries are just a single file, that you can drop directly into your application.
Some other libraries are more complex though, and almost require you to use Luarocks for installation, otherwise, you would need to hand-manage &lt;code&gt;LUA_PATH&lt;/code&gt; for each such library.
Which works, but not as great as it could be.&lt;/p&gt;
&lt;h3 id=&#34;varargs&#34;&gt;Varargs&lt;/h3&gt;
&lt;p&gt;As for language-side problems, I can think of only one that stands out in particular - the support for varargs &lt;code&gt;...&lt;/code&gt; and a multi-value return.
There&amp;rsquo;s a &lt;a href=&#34;https://benaiah.me/posts/everything-you-didnt-want-to-know-about-lua-multivals/&#34; target=&#34;_blank&#34;&gt;great article&lt;/a&gt;, going in-depth of vararg quirks, so I&amp;rsquo;ll keep it brief.
The main problem with varargs is that they&amp;rsquo;re not a first-class value.
You can&amp;rsquo;t properly store varargs without using a table, and given that varargs obey a bit different scoping rules it&amp;rsquo;s sometimes awkward to use them with higher-order functions.
For a better illustration here&amp;rsquo;s an implementation of a &lt;a href=&#34;https://clojure