<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Always Bet On Rust]]></title><description><![CDATA[A blog about a programming language refusing to stay in its lane]]></description><link>https://blog.abor.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!khrt!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F67719931-10cb-495c-9ba7-3dc67723c988_512x512.png</url><title>Always Bet On Rust</title><link>https://blog.abor.dev</link></image><generator>Substack</generator><lastBuildDate>Thu, 16 Apr 2026 17:38:01 GMT</lastBuildDate><atom:link href="https://blog.abor.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Josh Kuhn]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[abor@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[abor@substack.com]]></itunes:email><itunes:name><![CDATA[Josh Kuhn]]></itunes:name></itunes:owner><itunes:author><![CDATA[Josh Kuhn]]></itunes:author><googleplay:owner><![CDATA[abor@substack.com]]></googleplay:owner><googleplay:email><![CDATA[abor@substack.com]]></googleplay:email><googleplay:author><![CDATA[Josh Kuhn]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Rust Editor Experience Survey]]></title><description><![CDATA[Hello! I realize it&#8217;s been a while since my last newsletter, but that&#8217;s shortly going to change.]]></description><link>https://blog.abor.dev/p/rust-editor-experience-survey</link><guid isPermaLink="false">https://blog.abor.dev/p/rust-editor-experience-survey</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Sat, 30 Oct 2021 03:45:42 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/67719931-10cb-495c-9ba7-3dc67723c988_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello!</p><p>I realize it&#8217;s been a while since my last newsletter, but that&#8217;s shortly going to change. I&#8217;ve been working on a project that&#8217;s spun out some very interesting ideas and discussions and I plan to share them with you all fairly soon.</p><p>In the meantime, I created a <a href="https://www.guidedtrack.com/programs/kfqw8vs/run">Rust Editor Experience Survey</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> to get some feedback on how Rust developers edit code and what parts of their editing experience they like and dislike. I&#8217;ll make a followup post with the results of this survey soon.</p><p>Consider taking the survey even if you have only been a Rust developer for a short time, I&#8217;m very interested in all perspectives on this. It tends to take about 4-5 minutes to complete.</p><p></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p><a href="https://www.guidedtrack.com/programs/kfqw8vs/run">https://www.guidedtrack.com/programs/kfqw8vs/run</a></p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[What do shells do, and do we need them?]]></title><description><![CDATA[Diving into what shells do, what we use them for, and an introduction to unsh, the unshell.]]></description><link>https://blog.abor.dev/p/unsh</link><guid isPermaLink="false">https://blog.abor.dev/p/unsh</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Tue, 25 May 2021 17:06:11 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ec532329-3d4e-4094-9b3e-9ca827c33c12_239x194.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, <a href="https://blog.abor.dev/p/evcxr">I wrote about Evcxr</a>, a REPL and Jupyter notebook kernel for Rust. In that post, I made the assertion that shells are basically REPLs, and that we should replace REPLs with notebooks. I think that&#8217;s true, but I still think there is a place for something like a shell, albeit a very restricted one.</p><p>Like any technology that has been around for decades, shells have a lot of features and responsibilities that were gained through gradual accretion. If a shell does almost everything you want except for <em>this one thing I need right now</em>, there&#8217;s a heavy temptation to add that one thing and not reinvent everything from scratch. Do that long enough and you end up with some things that a shell does well, and lots of things it does less well but, you know, well enough.</p><p>Some people have looked at the deficiencies of the shell<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> and thought &#8220;How do we make this better?&#8221; Both <a href="https://fishshell.com/">fish shell</a> and <a href="https://www.nushell.sh/">nushell</a> are attempts to take what shells do and improve on it by making the shell more capable and its scripting language less crufty. In contrast, I think we should strip away responsibilities from the shell and hand them off to tools that are better suited.</p><p>Let&#8217;s take a look at what shells do, and see if we can tease apart what their strengths are and where other tools have come along and supplanted them. Then we can come back and see what&#8217;s left and see if there&#8217;s something better to be built. It&#8217;s usually a good idea to learn <a href="https://wiki.lesswrong.com/wiki/Chesterton%27s_Fence">what something is doing before tearing it down</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/subscribe?"><span>Subscribe now</span></a></p><h1>What capabilities do shells provide?</h1><h3>A way to spawn processes and pass startup options</h3><p>In functional languages like Haskell, applying a function to its arguments is the most common and important operation you&#8217;ll do, so the syntax is very lightweight. No parentheses, no commas, just spaces between the function and its arguments. <code>f a b</code> is the syntax for calling a function, which is equivalent to <code>f(a, b)</code> in most imperative languages<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. Removing that little bit of syntactic noise is worth it because function application is so central.</p><p>Likewise in a shell, spawning a process and passing it options is the central activity. Compare the way we invoke commands in a shell:</p><pre><code><code>$ echo hello world</code></code></pre><p>with how we call a process in Rust:</p><pre><code><code>std::process::Command("echo").args(&amp;["hello", "world"]).spawn();</code></code></pre><p>Shells have reduced their overall syntactic flexibility in order to make spawning processes maximally convenient. Simple things like arithmetic and if/then conditions are syntactically very noisy in shell scripts, but spawning processes and passing it <code>argv</code> is about as easy as it gets.</p><h3>A way to navigate the filesystem</h3><p>In a shell, using <code>cd</code> and <code>ls</code> are about the most common things I do. Specifically, <code>cd</code> is so common we might not often pause to consider that usually it&#8217;s a shell builtin and not a separate executable on the path. If you write a naive <code>cd</code> program and invoke it in a shell, it&#8217;ll just change the directory of the subprocess and then exit, leaving the shell&#8217;s current directory unchanged.</p><p>I have a graphical file explorer on my system, but I don&#8217;t often use it. When I want to navigate somewhere on the filesystem I usually want to invoke some commands in that directory immediately afterward. It&#8217;s much easier for me to just <code>cd some/directory</code> than to click my way there in a GUI.</p><h3>A default user interface for simple programs</h3><p>Don&#8217;t want to think about your user interface? Just output text. Most languages<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> make writing to <code>stdout</code> very easy, so it&#8217;s a very low friction way to allow your program to communicate with humans. For many programs that don&#8217;t need heavy interaction with the user, you accept arguments through the command line and output to <code>stdout</code>.</p><p>Imagine needing to construct a GUI text box in order to display output to a user. That would introduce a huge amount of overhead to creating small programs and testing things out. Instead the shell provides the default UI: text scrolls up as the program executes, which the user can scroll back through if they want. Then the shell returns to the prompt when the program exits.</p><p>There are downsides to this universal interface: it relies on the user having a gigantic library installed in their brain already: the entire human language your program is written in plus the ability to read the written form of that language. Most everyone can drag a slider or click a button, but a text interface is completely useless to someone who doesn&#8217;t know the language or how to read.</p><h3>A way to connect the output of one program to the input of another</h3><p>Besides spawning processes, this is the second thing the shell makes delightfully easy. The boundary between the pipe character and shell scripting language itself is a bit blurry, but it&#8217;s worth calling it out separately because all by itself it makes shells significantly more capable even without other programming language features like variables, loops and conditions.</p><p>It works really well because it turns out it&#8217;s the same thing as function composition. There are entire categories of math devoted to how much power you get just by composing functions. To make it explicit, here&#8217;s three things that are alternative syntax for the same thing:</p><pre><code>cat /dev/urandom | head -c 200 | base64</code></pre><pre><code>base64(head(cat(&#8220;/dev/urandom&#8221;), 200))</code></pre><pre><code>cat(&#8220;/dev/urandom&#8221;).head(characters=200).base64()</code></pre><p>Technically, processes return a second bit of information, the exit code, which makes this composition a little fiddly. But the basics are the same.</p><h3>A resizable 2D grid that can display characters in color</h3><p>This is getting into the border between the shell and the terminal emulator. Really it&#8217;s the terminal emulator that interprets various escape sequences and displays color and implements raw mode which enables writing to arbitrary character locations. But if we are willing to conflate shell and terminal emulator momentarily, command lines have the capability to create rudimentary graphical interfaces.</p><p>Sure we have to use some weird <a href="https://en.wikipedia.org/wiki/Box_Drawing_(Unicode_block)">box-drawing unicode characters</a>, but the limited graphical capabilities on par at least with xterm are expected by many common tools. I mean, heck, even <code>systemd status</code> uses color to indicate the status of services:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wu2U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wu2U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 424w, https://substackcdn.com/image/fetch/$s_!wu2U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 848w, https://substackcdn.com/image/fetch/$s_!wu2U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 1272w, https://substackcdn.com/image/fetch/$s_!wu2U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wu2U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png" width="853" height="204" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/cd2f52b4-5342-4b14-a730-be028dd15513_853x204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:204,&quot;width&quot;:853,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52284,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wu2U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 424w, https://substackcdn.com/image/fetch/$s_!wu2U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 848w, https://substackcdn.com/image/fetch/$s_!wu2U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 1272w, https://substackcdn.com/image/fetch/$s_!wu2U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd2f52b4-5342-4b14-a730-be028dd15513_853x204.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>A simple programming environment</h3><p>After piping, there are some basic programming features like variables, for loops, if statements etc. This is what tempts you to solve problems in a shell script rather than back up and realize you should switch over to solving the problem with a general purpose programming language.</p><p>The friction is so low though! Maybe by the time you&#8217;ve crafted half of the solution to your problem by piping shell commands together, there&#8217;s a little bit of sunk cost calculation going on. Do I really want to rewrite this entire thing over again in a completely different language, or should I just go look up <a href="https://serverfault.com/questions/52034/what-is-the-difference-between-double-and-single-square-brackets-in-bash">the difference between <code>[</code> and <code>[[</code></a> one more time and bang this thing out?</p><p>Personally, I think this is the original sin of the shell. It gives you just enough rope to hang yourself. Once you&#8217;ve solved your problem in a shell script, doesn&#8217;t it make sense to just commit that as your code? And once you&#8217;re committing your shell scripts, doesn&#8217;t it make sense to add a linter like <a href="https://www.shellcheck.net/">ShellCheck</a> to your CI pipeline? This is the point at which the slope begins to slip.</p><h3>A persistent global history buffer of previous commands</h3><p>This might seem like a minor point, but I regularly use my shell command history as a very limited second brain. Especially with fancy history autocompletion, this becomes a really powerful way to keep arcane program invocations stored&#8230; somewhere. And, in contrast to curating and storing your useful commands in a wiki or something (probably copy/pasting it back and forth), searching the command history automatically puts the command exactly where it needs to be to execute it immediately.</p><h3>A lowest common denominator execution environment</h3><p>Because it&#8217;s always available on *nix systems, shell scripts offer a language to bootstrap other features from. MacOS won&#8217;t execute <a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format">ELF</a> binaries, but if you wrap your downloader in a shell script like rustup does, you can intelligently interrogate the host system and download the appropriate binary file for it. This makes distributing tools like rustup much easier.</p><p>Build systems commonly use this strategy to decide which tools are available to execute with. For example, <a href="https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html">autotools</a> is essentially a gigantic shell script that checks the capabilities of a UNIX system extensively in order to determine the best way to compile a C program.</p><h2>What are shells to a human?</h2><p>So far I&#8217;ve talked about a bunch of technical capabilities and features of shells, but one layer above that is what roles shells play at a human level. By that I mean, what is a human trying to do when they reach for a shell? If there are two equivalent ways to do something, when do we choose to use a shell to do it?</p><h3>A place to execute non-GUI programs</h3><p>You could make the argument that the dividing line between an app and a program is whether you invoke it from the shell or not. Programs are available on your <code>$PATH</code>, not your desktop. They&#8217;re words you memorize and type out, not icons you click. They&#8217;re intended to be tools used in combination with other tools, not self-contained applications. The shell is how you access and configure programs like this.</p><h3>A sense of location</h3><p>When you cd into a directory, you are navigating there mentally. This is repurposing the brain&#8217;s well developed spatial awareness. From the computer&#8217;s point of view, absolute paths and relative paths are equivalent. From a human&#8217;s point of view, relative paths are a natural way of specifying directions that originate from a particular starting point.</p><p>You can see this effect in tools like <code>git</code>, which looks at the current directory to decide which project you&#8217;re working on. When non-technical users interact with computers, they usually don&#8217;t think of themselves being in a particular place in the filesystem. The location is either the desktop or an app. When you&#8217;re in the shell, you&#8217;re wherever your current directory is.</p><h3>A place to tinker and figure things out</h3><p>This is enabled by the REPL nature of the shell, and the interaction between the UNIX philosophies of <a href="https://en.wikipedia.org/wiki/Everything_is_a_file">everything is a file</a> and the capability of piping data around. When Brett Victor talks about <a href="http://worrydream.com/#!/LearnableProgramming">visual feedback and showing the data being more important than showing the code</a>, it becomes obvious that the shell provides a crude form of that.</p><p>The arcane invocation you&#8217;re building up piece by piece may be difficult to understand by reading it, but that&#8217;s because you&#8217;re not reading the code, you&#8217;re running the code and seeing what it outputs. The process is to incrementally build the code to get the answer you&#8217;re looking for.</p><p>A stylized workflow in this mode is something like:</p><ul><li><p>Do a basic query, see what the output looks like</p></li><li><p>Pipe the output into some program like <a href="https://www.tutorialspoint.com/awk/awk_basic_examples.htm"><code>awk</code></a> or <a href="https://stedolan.github.io/jq/"><code>jq</code></a> and start digging for the piece of the output you need</p></li><li><p>Use <a href="https://lornajane.net/posts/2011/navigating-bash-history-with-ctrlr"><code>Ctrl+R</code></a> and &#11014;&#65039; to modify the previous version incrementally and re-execute</p></li><li><p>Once the query portion is what you expect, simulate the write step by adding an echo that prints what command would be invoked</p></li><li><p>When you&#8217;re comfortable with that, swap out the echo for the actual write operation</p></li><li><p>Walk away. Don&#8217;t commit the result to source control or refactor, this is ephemeral write-only code for a one-off job</p></li></ul><h3>A place for hacker aesthetic</h3><p>I&#8217;d be remiss if I didn&#8217;t mention that things running in the shell have a certain aesthetic that many developers find pleasing. This demo for the terminal UI kit <a href="https://github.com/fdehau/tui-rs">tui-rs</a> is undeniably cool:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://github.com/fdehau/tui-rs" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xuCD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 424w, https://substackcdn.com/image/fetch/$s_!xuCD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 848w, https://substackcdn.com/image/fetch/$s_!xuCD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 1272w, https://substackcdn.com/image/fetch/$s_!xuCD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xuCD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif" width="720" height="416" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:416,&quot;width&quot;:720,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1427921,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:&quot;https://github.com/fdehau/tui-rs&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xuCD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 424w, https://substackcdn.com/image/fetch/$s_!xuCD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 848w, https://substackcdn.com/image/fetch/$s_!xuCD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 1272w, https://substackcdn.com/image/fetch/$s_!xuCD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F979fe33c-6bcc-4393-960f-1d4b92527191_720x416.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">tui-rs demo</figcaption></figure></div><p>Why is that? If someone made the same interface in a GUI toolkit, it wouldn&#8217;t look nearly as cool to me. I say this as someone who has used a shell daily for almost two decades, the novelty somehow hasn&#8217;t worn off.</p><p>If you want to build something with a terminal UI like this, your target audience is necessarily programmers and other technical users. Non-technical users are not going to put up with this stuff. The barrier to entry the shell puts up means programmers can have their dorky tools and make them the way they want, without anyone complaining that it looks ugly.</p><p>This also functions as a kind of costly signal: if a tool has an intricate terminal UI, it&#8217;s a good bet the creator of the tool cares about programmers. The code needed to write a terminal UI is just as complex as the code needed to output a basic html interface or use a standard OS GUI library. The difference is purely in the rendering layer, and the implicit message is &#8220;I&#8217;m rendering this for you, fellow hacker&#8221;</p><h2>What replaces the shell?</h2><p>This is a big topic and there are lots of answers, but I think we can point out some general replacements for aspects of what the shell does</p><h3>Terminal UIs become browser interfaces</h3><p>This trend is already happening. Terminals can be pressed into service to do graphical output, but human input in a terminal interface is abysmal. Browsers do input and output about equally well (that is to say: mediocre, but not badly).</p><h3>Explore and tinker in a programming language&#8217;s REPL or code notebook</h3><p>I mentioned this in <a href="https://blog.abor.dev/p/evcxr">the previous post</a>:  I&#8217;m a fan of the notebook concept over REPLs. But even a REPL in a good language is better than a REPL in a bad language (shell script).</p><h3>Use IDEs or code notebooks to provide task-oriented location</h3><p>IDEs also provide the metaphor of &#8220;project directory is where you are&#8221;, and code notebooks like jupyter do as well. You can change the current working directory in a notebook, but it rarely seems necessary because the implicit assumption is that the notebook file itself is in the directory you want to be in.</p><h3>Minimize serialization logic and lean more heavily on library interfaces</h3><p>This is a larger topic than I want to get into here, but the basic idea is that I think the UNIX toolbelt approach of making small, single responsibility tools that interact by piping plaintext to each other was a really good idea in the 70s, but we understand the problem domain better now and have myriad solutions for it.</p><p>Fundamentally, small tools communicating through plaintext has a few weaknesses:</p><ol><li><p>It makes serialization, de-serialization and validation code a larger proportion of what your program does. It also means you lose much of the benefits of a language like Rust with strong typing. Serialization and de-serialization are the boundaries where the type checker can no longer help you, so you want to minimize those, not maximize them.</p></li><li><p>For a tool to really be usable in this way, you need to commit to backwards compatibility. This means tools have a limited ability to evolve before they become ossified in order to prevent breaking things.</p></li></ol><p><a href="https://en.wikipedia.org/wiki/AWK"><code>awk</code></a>, <a href="https://en.wikipedia.org/wiki/Tr_(Unix)"><code>tr</code></a>, and <a href="https://en.wikipedia.org/wiki/Cut_(Unix)"><code>cut</code></a> are all programs for parsing ad-hoc underspecified serialization formats. Let&#8217;s do away with the need for them by using the much richer interfaces provided by modern programming languages&#8217; type systems and the <a href="https://serde.rs/">tooling they have for expressive and flexible serde</a>.</p><p>The alternative to small focused binaries communicating through plaintext is small focused libraries with richly typed interfaces.</p><h2>What&#8217;s left for the shell?</h2><p>I think this leaves the shell with:</p><ul><li><p>the default interface for simple programs</p></li><li><p>a place to spawn processes and provide configuration arguments</p></li><li><p>a cross-platform bootstrap environment</p></li></ul><p>I hope that as <a href="https://wasi.dev/">WASM+WASI</a> gains traction, it can take over the cross-platform bootstrapping capabilities. Or possibly something exotic like <a href="https://justine.lol/ape.html">Actually Portable Executables</a> will take root. But I don&#8217;t think shell scripts are a good long term solution for &#8220;write once, run anywhere&#8221;.</p><h2>Unleashing Unsh</h2><p>That leaves the default interface and process spawning responsibilities. To that end, I&#8217;ve written <a href="https://github.com/deontologician/unsh">unsh (short for Un-shell)</a>. All it does is provide a loop where you can execute programs, provide them with an argv, and see what their output is:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3-5H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3-5H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 424w, https://substackcdn.com/image/fetch/$s_!3-5H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 848w, https://substackcdn.com/image/fetch/$s_!3-5H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 1272w, https://substackcdn.com/image/fetch/$s_!3-5H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3-5H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png" width="504" height="96" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:96,&quot;width&quot;:504,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7917,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3-5H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 424w, https://substackcdn.com/image/fetch/$s_!3-5H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 848w, https://substackcdn.com/image/fetch/$s_!3-5H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 1272w, https://substackcdn.com/image/fetch/$s_!3-5H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1b28e153-cd8c-4f3b-b13e-8a03560c6220_504x96.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>It doesn&#8217;t have a programming language built in, and it doesn&#8217;t allow piping output:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-w-r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-w-r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 424w, https://substackcdn.com/image/fetch/$s_!-w-r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 848w, https://substackcdn.com/image/fetch/$s_!-w-r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 1272w, https://substackcdn.com/image/fetch/$s_!-w-r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-w-r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png" width="626" height="193" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/57289d28-7210-4b34-97cb-02de3018feb8_626x193.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:193,&quot;width&quot;:626,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20676,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-w-r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 424w, https://substackcdn.com/image/fetch/$s_!-w-r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 848w, https://substackcdn.com/image/fetch/$s_!-w-r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 1272w, https://substackcdn.com/image/fetch/$s_!-w-r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F57289d28-7210-4b34-97cb-02de3018feb8_626x193.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Is <code>unsh</code> useful? Well, sure if you need those two things, and nothing else. It&#8217;s designed to hint strongly to the user that if they want something more complicated, they should probably use a real programming language.</p><p>If you want to be hardcore, try switching your login shell to unsh and see how it goes. I think people may be surprised at how far simple process launching gets you, even without the rest of a shell&#8217;s capabilities.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/p/unsh/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/p/unsh/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/p/unsh?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/p/unsh?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Throughout I&#8217;m talking mostly about POSIX shells. Some of what I&#8217;m talking about is also applicable to <a href="https://docs.microsoft.com/en-us/powershell/scripting/overview?view=powershell-7.1">PowerShell</a>, but I haven&#8217;t been careful to call those places out (mostly because of my lack of familiarity)</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>This function call style seems to have been popularized by Fortran, and maybe even earlier by <a href="https://en.wikipedia.org/wiki/Plankalk%C3%BCl">Plankalk</a>, a language used in 1948. Though there&#8217;s some convergent evolution going on since mathematics used the<code> f(a, b) </code>syntax before computers were around. If anyone knows of a comprehensive history of this syntax, let me know!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>For some reason it always irked me that Java required one to do <code>System.out.println</code> just to put a string on the console.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Bonus material from Tim McNamara]]></title><description><![CDATA[Tim's spiciest takes on Haskell, Emacs and Data Science. Almost blockchains, I almost got him to talk about blockchains]]></description><link>https://blog.abor.dev/p/timclicks-bonus</link><guid isPermaLink="false">https://blog.abor.dev/p/timclicks-bonus</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Mon, 17 May 2021 16:41:41 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/90799edf-ad59-49a7-9721-cc2c63385aea_160x160.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the <a href="https://blog.abor.dev/p/timclicks">previous post</a> I talked with Tim McNamara, and just really had a lot of extra material left over I wanted to post somewhere. This is that somewhere.</p><p>On tech publishing:</p><blockquote><p>I had become really disillusioned with tech writing and with publishers pushing out content, which is like basically content marketing. So these database vendors, or like, let's say &#8230;</p></blockquote>
      <p>
          <a href="https://blog.abor.dev/p/timclicks-bonus">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Routes to Discovering Rust]]></title><description><![CDATA[A conversation with Tim McNamara, author of Rust in Action, on how he got into Rust by teaching himself everything from scratch]]></description><link>https://blog.abor.dev/p/timclicks</link><guid isPermaLink="false">https://blog.abor.dev/p/timclicks</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Sat, 15 May 2021 16:19:07 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1b5d04ec-ba47-419d-bcae-d7dbd17381f3_176x176.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The way I personally discovered Rust is sort of akin to <a href="https://www.lesswrong.com/tag/acausal-trade">acausal trade</a>:</p><blockquote><p>In <strong>acausal trade</strong>, two agents each benefit by predicting what the other wants and doing it, even though they might have no way of communicating or affecting each other, nor even any direct evidence that the other exists.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></blockquote><p>In grad school I spent a lot of time writing C to try to maximize throughput on some algorithm benchmarks for my thesis, and I really came to enjoy the language a lot. There is just so much control over exactly how things execute and how things are laid out in memory. I also spent a lot of time in grad school coding in Haskell, because I love learning new type system features and Haskell basically has an endless supply of those.</p><p>This left me in the strange position of simultaneously loving a low level language where you could almost feel the bits directly and which has almost no abstraction capability at all, while at the same time loving an ultra-high level, lazy, garbage collected language with a never-ending tower of abstractions. I constantly found myself wanting some aspect of the other language:</p><ul><li><p>C is just missing some straightforward, obviously good language features like <a href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types</a>, <a href="https://en.wikipedia.org/wiki/Closure_(computer_programming)">closures</a>, <a href="https://en.wikipedia.org/wiki/Type_inference">type inference</a>, and <a href="https://en.wikipedia.org/wiki/Parametric_polymorphism">generics</a></p></li><li><p>Haskell has this garbage collector and runtime and yet you still regularly run across space leaks due to laziness!</p></li></ul><p>Another grad student and I briefly investigated writing a non-garbage collected functional language but it looked to us like there wasn&#8217;t enough original research left to do. All of the hard parts had been thought up before, just nobody had combined them into a nice polished language. The closest thing was <a href="https://cyclone.thelanguage.org/">Cyclone</a>, a safe dialect of C that pioneered the use of <a href="https://en.wikipedia.org/wiki/Substructural_type_system#Linear_type_systems">linear types</a> to do safe memory management (which eventually <a href="https://pling.jondgoodwin.com/post/cyclone/">inspired the Rust borrow checker</a>). But Cyclone was also very obviously an academic research language, there was no big push behind it, and new code only got added to it when someone wanted to write a new paper.</p><p>So, for me, there was this <a href="https://stackoverflow.com/questions/6513806/would-it-be-possible-to-add-type-inference-to-the-c-language">puzzle piece that was obviously missing</a>, and it looked like someone would create it any day now, all I had to do was wait. It turns out, <a href="https://en.wikipedia.org/wiki/Graydon_Hoare">Graydon Hoare</a> had started work on Rust in 2006, but I wouldn&#8217;t have recognized it as that puzzle piece at the time. Rust still had garbage collection and an erlang-style <a href="https://en.wikipedia.org/wiki/Green_threads">green thread</a> runtime back then. It wasn&#8217;t until after <a href="https://pcwalton.github.io/2013/06/02/removing-garbage-collection-from-the-rust-language.html">Patrick Walton&#8217;s 2013 blog post</a> that Rust shed its garbage collector and most of its runtime and became the language as we think of it today.</p><p>I found Rust shortly after that in 2014 and, I guess the acausal trade was complete? A bunch of really smart and dedicated people had done all the hard work of creating and polishing a very nice language that satisfied all my requirements. In return I, uh&#8230; did nothing. Ok well maybe it was less of an acausal trade and more of an acausal gift<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>But, I recognize this is not a super typical route to discovering Rust. Although, since most people writing Rust are doing it in their free time rather than at their jobs (currently), there might not actually be a typical way to get into Rust. I recently spoke with <a href="https://github.com/timClicks">Tim McNamara</a>, author of <a href="https://www.manning.com/books/rust-in-action">Rust in Action</a>, and he talked about his own route to the language:</p><blockquote><p><em>My career path has been really, let's say non-linear. Quite weird. </em></p><p><em>I have an undergraduate degree in philosophy and German.&#8203; A BA from a university that <a href="https://www.atlasobscura.com/articles/new-zealand-left-off-world-map">no one&#8217;s heard of at all because it&#8217;s from New Zealand.</a> I also got a master's in public policy as well for various reasons. I was destined to be an official basically.</em></p><p><em>I spent several years as a data scientist doing some really quite neat things with text and search and so forth. I worked for <a href="https://canonical.com/">Canonical</a>, the company behind <a href="https://ubuntu.com/">Ubuntu</a> for a couple of years as well. But, I just really enjoyed playing with data, so now I work as a senior data scientist at a <a href="https://www.dragonfly.co.nz">small (actually relatively large now) consultancy</a> here in New Zealand.</em></p><p><em>I got into Rust sort of sideways. I've been a Python developer, I guess, for about a decade. Five-ish years ago now, it just sort of started kind of creeping up on me, this idea that I'm leaving a lot of performance on the table. I'm a relatively proficient Python developer, but, you know, people sort of always whisper that, &#8220;<a href="https://docs.python.org/3/extending/extending.html">C extensions</a> are where it&#8217;s at.&#8221; Like if you're using Python you're always missing out.</em></p><p><em>But I was always told that like&#8230; C is dangerous. You should never basically write C extensions because that's reserved for wizards and experts and you're not an expert. So you should not even try because you&#8217;ll create some sort of <a href="https://en.wikipedia.org/wiki/Segmentation_fault">segfault</a>, destroy your whole computer, or destroy the world (or expose your users to some pretty needless security concerns). So, I was always terrified of C.</em></p><p><em>My first playing around with Rust was doing <a href="https://en.wikipedia.org/wiki/Natural_language_processing">natural language processing</a>. Carving up a lot of text and converting it into big arrays of matrices of numbers, which was the input to a lot of these machine learning models which I can reuse in the Python world.</em></p><p><em>I got a 100x speed up, like, just by doing this Rust thing.&#8203; And also, memory is like megabytes, instead of gigabytes. There was this massive mental shift that goes on, &#8220;Well actually, Rust is </em>really<em> good.&#8221;</em></p></blockquote><p>At the same time, he had a bubbling interest in what was going on at the lowest levels of software</p><blockquote><p><em>This is actually quite magical. My computer can talk to almost every other computer in the world and we just expect it to work and like&#8230; how does it work? It's so commonplace that it almost feels like we don't really consider the complexity that goes on when you click the enter key on a keyboard.</em></p><p><em>And yet, it actually initiates a massive cascade of events that enables pixels to be rendered on the screen or to do whatever needs to happen when that event occurs.</em></p></blockquote><p>This led him to start writing Rust in Action, where he was able to explore some of these questions in depth. Sometimes one investigation led him to further topics and he just kept digging</p><blockquote><p><em>The database chapter started out with the files chapter. I was like, how does a computer represent these data structures actually? How are they represented in a serial string on disk? In memory everything's hierarchical and there&#8217;s pointers everywhere and so forth. So we kind of need to flatten everything out.</em></p><p><em>How do databases do things like ensure that your data is safe, even if the hardware, like the underlying platform, might lose power or become corrupted? You know, if you can't trust anything, how do you ensure that your data is safe?</em></p><p><em>So the full version, which is kind of still sitting on my computer, it's like this full, really interesting <a href="https://en.wikipedia.org/wiki/B-tree">B-Tree</a> structure and like, it's quite elaborate. So we implement pretty cool semantics on top of a key value store.</em></p></blockquote><p>Writing the book was the impetus behind exploring these topics, but the book format has limitations that he ran up against</p><blockquote><p><em>I always have a little bit of a lament&#8212;kind of like a little bit of regret that I wasn't able to insert the full version of things. I can't explain everything there is to know about systems programming in a book about Rust. Like, I can wedge a lot in there, but&#8230; I can't write every book in one book.</em></p><p><em>Turns out that if you&#8217;re writing a chapter, readers are not really interested in, like, 90 page chapters. I don&#8217;t think they&#8217;re going to have the patience for me teaching them everything about databases and database internals.</em></p><p><em>You kind of need to whittle it down to only introduce one new Rust feature in every example. I can't introduce four new Rust concepts. I couldn't introduce like <a href="https://doc.rust-lang.org/book/ch13-01-closures.html">closures</a> and <a href="https://doc.rust-lang.org/std/result/"><code>Result</code></a> at the same time. There are definitely people who have come to me and been like &#8220;Well this is a stretch.&#8221;.</em></p><p><em>I recognize that I'm not going to be able to write a single piece of tech writing that is going to be perfect to everyone. It&#8217;s just something that I've kind of had to acknowledge.&#8203; I started out with this very grandiose idea that I could write the very best tech book, like, in the world.</em></p><p><em>I felt for myself that I would really produce something extremely high quality. And, I think one of the hardest things has been that I've constantly felt that it&#8217;s not quite good enough.</em></p><p><em>There was this case where I thought a section would be a couple pages, and then like I&#8217;m a hundred pages in now. Thankfully for my readers, my editors were very pragmatic and said &#8220;Tim, you gotta&#8230; this is crazy.&#8221;</em></p></blockquote><p>We also talked a bit about the audience for the book, and the message he wants to convey through it</p><blockquote><p><em>If you're anything like the person that I was a couple of years ago, like inquisitive about how computers work or really interested in understanding, like, &#8220;What is a pointer?&#8221; &#8220;What does it mean for a reference to be dereferenced?&#8221; things that are kind of like this tacit knowledge, which is assumed by people within the Rust community. That&#8217;s the kind of stuff you really get.</em></p><p><em>My intention is to put people at ease when they enter the Rust community. People talk about <a href="https://en.wikipedia.org/wiki/Substructural_type_system#Affine_type_systems">affine type systems</a> and a whole bunch of jargon. This is kind of the resource that people can look to as giving a base level of understanding when someone says &#8220;We&#8217;ve got to use a <a href="https://en.wikipedia.org/wiki/System_call">syscall</a> for that.&#8221;</em></p><p><em>If anyone is looking at Rust and thinking &#8220;Man, these people are really smart and I&#8217;m not smart&#8221;. That is the mentality I want to bridge and say &#8220;No, actually, you&#8217;re welcome. You&#8217;ve got a place at the table.&#8221; The Rust community is available to you, and Rust is a resource that you can use to keep your programs fast and your users safe.</em></p></blockquote><p>Given he&#8217;s a data scientist, I asked him what he thought of doing data science in Rust</p><blockquote><p><em>I think that Rust is going to struggle with the data science for sort of two reasons. I think primarily the ergonomics question is the problem. R and Python are always just going to feel a little bit more fluid.</em></p><p><em>I'm a very strange data scientist in that I have invested very heavily in understanding the software tools that I use and the world of software that I inhabit. But most data scientists do not take much time to think about software engineering as a&#8230; as a thing<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. There's this new term called data engineer, which is probably where I sit.</em></p><p><em>Now, within Rust, I think things like <a href="https://www.tensorflow.org/">TensorFlow</a> should probably be written in Rust. I would love to see <a href="https://kafka.apache.org/">Kafka</a> implemented in Rust and, and <a href="https://zeromq.org/">ZeroMQ</a> and these messaging systems and log aggregation and kind of a lot of this boring stuff that enables data to be stored and transmitted and analyzed.</em></p><p><em>I think <a href="https://andygrove.io/about/">Andy Grove</a> has done a really amazing job. He&#8217;s been shipping Rust inside the <a href="https://arrow.apache.org/">Apache Arrow</a> project. So Apache Arrow was originally an attempt at creating a kind of peace between the Python and R worlds of data scientists by creating an in-memory format for being able to kind of send data structures between Python and R without costs.</em></p><p><em>Andy had this idea of reimplementing what we would have a couple of years ago said <a href="https://hadoop.apache.org/">Hadoop</a>, but more recently we would say implementing <a href="https://spark.apache.org/">Spark</a> with this project built on Arrow called <a href="https://github.com/ballista-compute/ballista">Ballista</a>.</em></p><p><em>So, these kind of big, heavy pieces that are infrastructure for data science, I think is where Rust is going to find itself very welcome. I think it will be very challenging for Rust to try to be Python. I think that <a href="https://julialang.org/">Julia</a> has a much better story as like a convenient, fast language for interactive use. You <a href="https://blog.abor.dev/p/evcxr">talked with the creator of the Rust kernel for Jupyter notebooks</a>. And I think that is an enabler, but I don't think it's enough. Being able to interact and introspect variables and so forth is important too.</em></p></blockquote><p>Apart from the book, where does he use Rust?</p><blockquote><p><em>It was interesting that you <a href="https://blog.abor.dev/p/making-generative-art-with-rust">interviewed Alexis</a> because creative coding is one of the things that I also play around with. There&#8217;s a <a href="https://www.youtube.com/watch?v=xDrAncijBq4&amp;list=PLwtLEJr-BkXbscQZLpvCvgYMtkoTCCDyR">couple of YouTube clips</a> where I go the tutorial for <a href="https://nannou.cc/">Nannou</a>, which is the framework you were discussing before. So that&#8217;s kind of like side projects.</em></p><p><em>At work, we&#8217;re slowly going through the process of optimizing. For like utilities or stuff that is being used repeatedly, I will gently nudge work, &#8220;If we want something that's reliable and easy to deploy and can use like a micro instance rather than like some big VM on the cloud&#8221;, I&#8217;ll nudge them towards Rust. So, it's been a process of finding things that are very discrete and slowly kind of finding a spot for Rust. Either as a replacement or as like a supplement to things that are typically implemented first in Python.</em></p><p><em>Typically, it&#8217;s in <a href="https://en.wikipedia.org/wiki/Command-line_interface">CLI</a> utilities or <a href="https://en.wikipedia.org/wiki/Extract,_transform,_load">ETL</a> which is the data transformation pipeline.</em></p></blockquote><p>What is he excited about in either the language or Rust ecosystem?</p><blockquote><p><em>I honestly feel that WebAssembly plus <a href="https://wasi.dev/">WASI</a> is going to be the standard way that we ship software in some future state. That&#8217;s where I feel most excited for Rust.</em></p><p><em>One of the things that I'm delighted to see is the way in which the Rust language developers have <a href="https://blog.rust-lang.org/2021/04/14/async-vision-doc-shiny-future.html">embraced the async discussion</a>.</em></p><p><em>I would love for that mental tax of async to kind of evaporate. I don't know if that's actually going to occur. I'm sure that it won't be perfect, but all the signs are there. The people taking the right approach like <a href="https://github.com/nikomatsakis">Niko</a> and <a href="https://github.com/rylev/">Ryan Livek</a> and others are very focused on creating a structure that would enable Rust to become the most pleasant async programming environment that the world has.</em></p></blockquote><p>On his development setup and tooling:</p><blockquote><p><em>I have a surprisingly boring setup. I&#8217;ve got a Dell XPS 15, and <a href="https://code.visualstudio.com/">VSCode</a> with <a href="https://rust-analyzer.github.io/">rust-analyzer</a>.</em></p><p><em>Like, I kind of wish I was a wizard, but really I found the Rust tooling, just the default stuff, to be really good. I did pay for <a href="https://www.jetbrains.com/clion/">CLion</a>, but one reason I don&#8217;t use it is that I do a lot of stuff on <a href="https://www.twitch.tv/timclicks">Twitch</a> and <a href="https://www.youtube.com/c/timClicks">YouTube</a>. And I want to make sure that my content is really accessible. And if I use proprietary paid technology, which a couple of my earlier videos did, it kind of creates a barrier that I don't think should exist.</em></p></blockquote><p>He also had some advice for newer Rust developers</p><blockquote><p><em>It's okay not to use idiomatic Rust. If you're a Java developer or if you've done C# or whatever other programming paradigm you're from, you are going to naturally write Rust that looks a little bit like Java or C#, you know, that's just what happens.</em></p><p><em>You are going to write <a href="https://blog.jooq.org/2013/01/12/bloated-javabeans-part-ii-or-dont-add-getters-to-your-api/">getters</a> that to me look hideous, like you're going add, <code>getThing</code>. But that's my problem as someone who's an experienced Rust user. I am going to squirm a little bit when I see your code and that's fine actually, because you do not need to learn everything in one go. Don&#8217;t aim for perfection if you&#8217;re starting out.</em></p></blockquote><p>Finally, to appease the <a href="https://www.reddit.com/r/rustjerk/">Rust Evangelism Strikeforce</a>, I have to include some effusive praise for the language:</p><blockquote><p><em>Normally I expect a technology to have this two year honeymoon phase, and then things start to really irritate you. I just am waiting for this disillusionment to occur, but with Rust, it just feels like I'm just continually excited.</em></p><p><em>It can enable you to build cool software and safe software and that's all important, but actually being able to kind of grow people as humans, I think is one of the things that's a really strong distinguishing characteristic of the language and its ecosystem more generally.&#8203;</em></p></blockquote><p>And because there must be balance in the universe:</p><blockquote><p><em>I get in trouble sometimes because I'm not a very good language evangelist. Rust is really pedantic and it can feel very bureaucratic and stuffy. Sometimes you just want Rust to relax. But it&#8217;s never going to relax.</em></p></blockquote><h2>Where to find Tim</h2><p>You can find his book <a href="https://www.manning.com/books/rust-in-action">Rust In Action on Manning&#8217;s site</a> and you can find him on Twitter <a href="https://twitter.com/timclicks">@timClicks</a> and see his streams on YouTube at <a href="https://www.youtube.com/c/timClicks">timClicks</a>. He also has a blog about technical topics at <a href="https://tim.mcnamara.nz/">tim.mcnamara.nz</a></p><h2>Upcoming posts</h2><p>Tim was a very fun person to talk to, and he gave me lots of (spicy?) opinions on things like Haskell, Emacs and data science that I am going to break into a separate post for subscribers.</p><p>If you&#8217;re interested in that kind of thing, feel free to subscribe. It does not have a lot to do with Rust, it was just a long conversation with lots of fun tangents and I wanted to collect the tidbits somewhere.</p><p>I also have a post coming up about doing constructive math and type theory in Rust, which Yay!, but also, sorry Tim.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share Always Bet On Rust&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share Always Bet On Rust</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>If you are going to bug me about how acausal trade sounds ridiculous&#8230; I am going to agree with you and continue to use it metaphorically.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Better than a <a href="https://en.wikipedia.org/wiki/Pascal%27s_mugging">mugging</a></p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>&#128293;</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Rust on the Frontend and Backend]]></title><description><![CDATA[An interview with Martin Kav&#237;k, creator of the MoonZoon full-stack framework]]></description><link>https://blog.abor.dev/p/moonzoon</link><guid isPermaLink="false">https://blog.abor.dev/p/moonzoon</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Fri, 07 May 2021 19:32:50 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e552f102-3dac-4734-8df2-0a9d76ad0ae8_362x300.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Backend languages in the browser have been a thing for a long time. <a href="https://en.wikipedia.org/wiki/Google_Web_Toolkit">Google Web Toolkit</a> would compile Java applications into JavaScript, and I believe (though I may be misremembering this<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>) that .NET had a feature where you could essentially code as if you were writing a form application in C# and it would compile to a web form and wire up JavaScript, HTML and CSS so you never had to learn anything about web technologies.</p><p>Things changed in a couple ways when Mozilla created <a href="https://en.wikipedia.org/wiki/Asm.js">asm.js</a> (leading later to <a href="https://webassembly.org/">WebAssembly</a>). Along with <a href="https://emscripten.org/">Emscripten</a>, you could now compile C and C++ into a subset of JavaScript that executed very efficiently and provided the kind of linear memory model that C backends expect. Generated JavaScript can have pretty bad performance characteristics, so being able to take advantage of decades of research in optimizing compilers for C and C++ in the browser was a big step forward.</p><p>Rust uses LLVM, which Emscripten compiles into WebAssembly, so pretty early after the creation of WebAssembly, people were porting Rust to work in the browser. And very shortly after that, there were Rust frontend frameworks.</p><p>What&#8217;s the difference between Rust frontend code and say, Flash, which was a compiled binary being executed in the browser? Aside from the plugin not shipping with the browser, the main difference is that Rust on the web is designed to integrate with the other APIs in the browser. Specifically, the DOM. Previous generations of frameworks tried to paper over the web and pretend it was just like any other GUI application.</p><p>While frontend frameworks are taking web technologies seriously now, it&#8217;s also the case that WebAssembly is the result of the web<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> taking languages other than JavaScript seriously. I&#8217;m personally a fan of <a href="https://www.typescriptlang.org/">TypeScript</a> in the category of &#8220;JavaScript but with a little extra&#8221;, but if you&#8217;re already stuck with a compilation step, why be so concerned with whether the input language resembles JavaScript?<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a></p><p>Rust has a reputation of giving low level performance with high level language features. Does that translate into a big advantage on the web? Yeah, there are some performance benefits, but it&#8217;s important not to overstate them. The biggest costs on the frontend are less in &#8220;how many loop iterations can I do per second&#8221; and more like &#8220;how do I avoid <a href="https://developers.google.com/speed/docs/insights/browser-reflow">reflows</a> and batch my DOM updates&#8221;. This varies depending on what kind of application you&#8217;re writing, but just like on the backend where we don&#8217;t worry too much about language overhead if you&#8217;re IO bound, running a more efficient language on the frontend doesn&#8217;t buy you much if all your time is spent blocking on the DOM.</p><p>Frameworks mitigate much of this on the web. They take care of batching your DOM updates and calculating the minimal set of event listeners that need to be inserted, etc. I&#8217;ll write up a better post on these things later, but the bleeding edge of these techniques was pioneered by <a href="https://svelte.dev/">Svelte</a>, which requires a compilation step. We now have tech similar to this in Rust as well with the <a href="https://github.com/Pauan/rust-dominator">dominator</a> library, which <a href="https://github.com/MoonZoon/MoonZoon">MoonZoon</a> utilizes in its frontend to get performance.</p><h2>Interview with Martin Kav&#237;k</h2><p>I spoke with <a href="https://github.com/MartinKavik">Martin Kav&#237;k</a>, the current maintainer of the <a href="https://seed-rs.org/">Seed</a> frontend framework and creator of a new full-stack framework called MoonZoon. We talk about how he chose Rust, becoming the maintainer of the Seed framework and some of the architecture and design decisions he made in MoonZoon.</p><p>The following interview was edited for length and clarity, and incorporates some followup questions I asked him.</p><p><strong>Can you talk a bit about how you got into Rust development?</strong></p><p><em>Yeah, I was working in some agencies in Prague in the Czech Republic and I was working with PHP and C/C++ and so on. And it was kind of dangerous. When our app got deployed to production, we&#8217;d very often find some problems that were very surprising bugs because of missing language features.</em></p><p><em>So I was trying to find a better language to eliminate these kinds of bugs, and I tried to learn <a href="https://elm-lang.org/">Elm</a>, <a href="https://elixir-lang.org/">Elixir</a>, <a href="https://golang.org/">Go</a> and so on. But I just didn&#8217;t like these languages. There were some very clever and nice things, but they were very dogmatic or too universal or designed for beginners (for example, Go). But then I found Rust, and that was it.</em></p><p><em>It&#8217;s the best language (I think), so I wanted to write in Rust and not use any other languages.</em></p><p><strong>You&#8217;re the primary maintainer of Seed, how did you get involved with the project?</strong></p><p><em>I was a frontend developer for some years, but there was only JavaScript there, so I moved to the backend. But after years of working in agencies and banks and similar companies, I wanted to move back to frontend because I was a bit tired of devops and microservices.</em></p><p><em>I was trying to find something like Elm, but in Rust. I tried a new framework, <a href="https://github.com/yewstack/yew">Yew</a></em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a><em> and some similar ones, but they felt a little too hard to learn, a little too cumbersome, I didn&#8217;t like the API or they were missing documentation. Then I found Seed, and I didn&#8217;t really like the code, but the API was very good.</em></p><p><em>So, I wrote some pull requests to Seed, and the owner was <a href="https://github.com/seed-rs/seed/pull/95#issuecomment-487425229">pretty happy</a> to merge them. That was my first Rust contribution to both GitHub and to open source in Rust. Then I saw the opportunity to rewrite and improve the codebase and API because the previous maintainer made me a provisional contributor. He was very good at designing the APIs because of their simplicity.</em></p><p><strong>What led you to developing MoonZoon?</strong></p><p><em>After maybe two years of development on Seed, I was able to write Rust pretty confidently. I had an idea that <a href="https://dev.to/martinkavik/moonzoon-dev-news-2-live-demo-zoon-examples-architectures-2oem#frontend-framework-architectures">some of the problems with JavaScript architectures in Rust</a> aren&#8217;t really solvable without many breaking changes in Seed&#8217;s users&#8217; applications.</em></p><p><em>So, I had two options. The first one was to refactor and introduce many changes in Seed&#8217;s codebase and API. Or I could write another framework (or proof of concept at least) of something better, with a newer and more Rusty architecture without Elm&#8217;s influence. That was the motivation for Zoon, MoonZoon&#8217;s frontend part.</em></p><p><em>The second problem was I received many questions about frontend and backend integrations on <a href="https://discord.gg/JHHcHp5">Seed&#8217;s chat</a>, and I wasn&#8217;t really able to answer them because there are too many frameworks and architectures on the backend side. Seed, or any other frontend frameworks, have to be flexible enough to support all of these frameworks.</em></p><p><em>So, I was thinking about how to resolve it once and for all, and the idea of one backend and one frontend was born. MoonZoon is solving the problem of integration, basically. The idea is the developer writes the application in MoonZoon, and it just works because it&#8217;s optimized for this small scope where you write the frontend and backend at once.</em></p><p><em>I was thinking about something like Apple&#8217;s technologies where they design the hardware and software, so they can optimize it much better than, for example, Windows where they have to deal with many kinds of hardware. That&#8217;s the basic idea.</em></p><p><strong>Has using Rust caused you difficulties specifically?</strong></p><p><em>Rust is a hard language to learn, and that has some advantages and disadvantages. The advantage is that it automatically filters, uh&#8230;, script kiddies, basically. So if you want to hire someone to write Rust for you, it&#8217;s pretty safe. They&#8217;ll already know how to program because it&#8217;s hard.</em></p><p><em>For particular Rust features, I was fighting for months with standard things like the borrow checker and lifetimes. And then you discover some feature with traits or some new features in the language and it&#8217;s kind of like relearning the language. So you have to learn constantly.</em></p><p><em>For example, when the <a href="https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html">async/.await</a> syntax was new, we had to rewrite the Seed codebase, especially for the <a href="https://seed-rs.org/0.8.0/time_tracker_fetch">fetch API</a>. We ran into some weird problems with the <a href="https://webassembly.org/">WASM</a> file being <a href="https://github.com/servo/rust-url/issues/557#issuecomment-544917435">too big</a> because we added some dependencies like <a href="https://crates.io/crates/url">standard url</a>. That dependency was too big, so we had to remove it and basically rewrite it from scratch. Problems or bugs, not particular to the language, but in dependencies and the ecosystem are the most painful things to resolve.</em></p><p><em>Most questions from Seed users or bugs in Seed apps are not due to the language itself; something like <code>null</code> or <code>undefined</code>. They&#8217;re just from semantic errors: they just can&#8217;t make it compile.</em></p><p><em>I think Rust has pretty different problems from JavaScript or PHP. So, you explain and they take this into account, that we will have to rely on the compiler. It&#8217;s new thinking for many many people from other languages and backgrounds.</em></p><p><strong>You mentioned earlier that you just wanted to code in Rust from now on, do you mean literally, or do you think there are some places where you would still use another language over Rust?</strong></p><p><em>Maybe there are some places where other languages will be a little bit better, but there are two problems for me. The first one is that my brain is comfortable with Rust. I don&#8217;t try to do the compiler&#8217;s work in my head. So, for example, when I was working for some months in a company where they were using Go. I would have everything running and working, and I would receive code review comments about something like missing references, or &#8220;This will maybe work, or maybe won&#8217;t work because of X&#8221;.</em></p><p><em>Rust eliminates these kinds of bugs with its features. In other languages there isn&#8217;t this safety net, so I had problems writing in these languages. Afterwards, I would like to write everything in Rust, because it&#8217;s basically a systems language for very low-level stuff, but we&#8217;re also able to write very nice abstractions with it. And you can compile it to native or anything else.</em></p><p><em>So, Rust everywhere for me.</em></p><p><strong>What features are you personally most excited about adding to MoonZoon?</strong></p><p><em>I&#8217;m writing the &#8220;Zoon&#8221; part of MoonZoon, so I ended up writing a <a href="https://github.com/MoonZoon/demo/blob/7e1c8aa343b636dacc9a945de4f7b95622209158/frontend/src/lib.rs">JS benchmark example app for Zoon</a></em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a><em>. I&#8217;m already seeing the differences between Seed and Zoon, for example, displaying thousands of lines on the screen. When you click on one row, it changes basically immediately in the Zoon app, but in the Seed app you need to wait for it to render the entire page. There are some architectural features paying off that I&#8217;ve already seen, so that&#8217;s pretty exciting for me. That&#8217;s maybe a few months away.</em></p><p><em>The &#8220;Moon&#8221; part, the backend, that&#8217;s basically a new world for me because I was working on Seed for the last couple of years. I haven&#8217;t been able to find another Rust <a href="https://www.microsoft.com/en-us/research/project/orleans-virtual-actors/">virtual actor</a> framework</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a><em>. There are some frameworks with virtual actors in <a href="https://github.com/orbit/orbit">Java</a> and <a href="https://www.microsoft.com/en-us/research/project/orleans-virtual-actors/">C#</a>, but that&#8217;s something that&#8217;s missing in Rust. So it&#8217;ll be from scratch and I&#8217;ll be reading white papers and trying to implement it. The goal is to make it scalable and make it work without a database. So I&#8217;m excited because it will allow me to write web applications without Postgres and migrations and DB-ops and similar stuff.</em></p><p><strong>Can you give a quick summary of how virtual actors work?</strong></p><ul><li><p><em>Actor Model</em>: An actor is an object that interacts with the world and other actors using asynchronous messages.</p></li><li><p><em>Standard Actors</em>: the actor has to be explicitly created and removed by a  developer or by the actor's parent (aka supervisor) by predefined rules.</p></li><li><p><em>Virtual Actors</em>: A runtime system manages actors. It creates, removes or moves actors between servers. All actors are always active and cannot fail from the developer point of view. In the case of hardware failure, the lost actors are automatically recreated on another server and messages forwarded to them.</p></li></ul><p><strong>That&#8217;s interesting, so in other words it will pull the database into the framework itself so it&#8217;s not talking to an external service?</strong></p><p><em>When you write a small application with a backend, you&#8217;ll be able to use virtual actors. But I know many apps will require some communication with some custom APIs (microservices or cloud APIs, something like that). So there will be some libraries to communicate with classic, standard APIs, but if you don&#8217;t need it you just use virtual actors and you&#8217;ll have scalability and basic stuff with authentication built in. It should make your development much faster and less complicated. Less setup for your local machine, and production should be less painful.</em></p><p><strong>Are there any projects in the Rust ecosystem that you think are really interesting but maybe haven&#8217;t gotten enough attention?</strong></p><ul><li><p><em>The first one is <a href="https://github.com/thedodd/trunk">trunk</a>. It&#8217;s like <a href="https://webpack.js.org/">WebPack</a> for Rust applications. The maintainer is a Seed user, so we know each other from the chat. I&#8217;ve already used trunk in a production app for my client, so it&#8217;s already working and usable with Seed and Yew (and probably other frameworks).</em></p></li><li><p><em><a href="https://docs.rs/futures-signals/0.3.20/futures_signals/tutorial/index.html"><code>futures-signals</code></a> is super nice and is basically the core of Zoon now</em></p></li><li><p><em>Another is <a href="https://whatlang.org/">whatlang</a>, an application built in Seed that uses natural language detection.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gjY7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gjY7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 424w, https://substackcdn.com/image/fetch/$s_!gjY7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 848w, https://substackcdn.com/image/fetch/$s_!gjY7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 1272w, https://substackcdn.com/image/fetch/$s_!gjY7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gjY7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png" width="1456" height="779" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:779,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79691,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gjY7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 424w, https://substackcdn.com/image/fetch/$s_!gjY7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 848w, https://substackcdn.com/image/fetch/$s_!gjY7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 1272w, https://substackcdn.com/image/fetch/$s_!gjY7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3df8dd2f-5ce7-42b1-8b1d-9a86d38fb321_1770x947.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div></li><li><p><em>Finally, <a href="https://github.com/BurntSushi/fst">fst</a> is pretty breathtaking. I was working on a frontend for a client in Rust, and the core was based on this library. I was able to search through maybe 20,000 movies by titles in a few milliseconds. When I was comparing it with some JavaScript libraries, they were taking maybe tens of milliseconds. So it&#8217;s a very nice example where Rust and WebAssembly is much faster and allows you to change your frontend architecture. You can move your search from the backend to the frontend side and save some money!</em></p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share Always Bet On Rust&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share Always Bet On Rust</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/subscribe?"><span>Subscribe now</span></a></p><h2>Updates &amp; Housekeeping</h2><p>If you have a paid subscription and haven&#8217;t gotten your Always Bet on Rust sticker yet, fear not, I&#8217;m sending the rest out this week.</p><p>Also, if you know someone who works on an interesting Rust project you think would make a good post please let me know. I have a pipeline of new interviews, but the suggestions I&#8217;ve gotten so far have been great.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>If someone can tell me what the heck I&#8217;m remembering here, please ping me</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Who is &#8220;the web&#8221;? Uh, the complex interacting system of standards bodies, web developers and browser makers that somehow form distributed consensus on which tech should exist, is implemented, and is well supported. Plus <a href="https://en.wikipedia.org/wiki/Brendan_Eich">Brendan Eich</a>. Ok there, I did it.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>There are actually benefits to this approach, which is that browser JITs are very optimized for JavaScript and JavaScript-like patterns. Additionally, you get a high quality garbage collector for free, which WebAssembly doesn&#8217;t give you.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>The <a href="https://moonzoon-demo.herokuapp.com/">benchmark demo</a> is pretty fun to play around with</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>Rust has several actor frameworks like <a href="https://github.com/actix/actix">Actix</a> and <a href="https://github.com/bastion-rs/bastion">Bastion</a>, but virtual actors are a specific type of actor framework described in <a href="https://www.microsoft.com/en-us/research/publication/orleans-distributed-virtual-actors-for-programmability-and-scalability/?from=http%3A%2F%2Fresearch.microsoft.com%2Fapps%2Fpubs%2Fdefault.aspx%3Fid%3D210931">this whitepaper</a> by Microsoft.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>Yew is another popular frontend framework for Rust</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Making Generative Art with Rust]]></title><description><![CDATA[Artists as technical experts and an interview with generative artist Alexis Andr&#233;]]></description><link>https://blog.abor.dev/p/making-generative-art-with-rust</link><guid isPermaLink="false">https://blog.abor.dev/p/making-generative-art-with-rust</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Fri, 30 Apr 2021 22:41:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!I-_z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://youtu.be/LkMzujVfVZ8" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I-_z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 424w, https://substackcdn.com/image/fetch/$s_!I-_z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 848w, https://substackcdn.com/image/fetch/$s_!I-_z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 1272w, https://substackcdn.com/image/fetch/$s_!I-_z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I-_z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png" width="1309" height="1305" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1305,&quot;width&quot;:1309,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1671678,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://youtu.be/LkMzujVfVZ8&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I-_z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 424w, https://substackcdn.com/image/fetch/$s_!I-_z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 848w, https://substackcdn.com/image/fetch/$s_!I-_z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 1272w, https://substackcdn.com/image/fetch/$s_!I-_z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ed870cf-9cf2-47c5-a29a-4ff5b2c8a458_1309x1305.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Face reveal 2020.</figcaption></figure></div><p></p><p>This post has some art in it, which you absolutely need to click through and go watch, because it&#8217;s meant to be seen in motion, and is pretty amazing. All images in this post are courtesy Alexis Andre.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/subscribe?"><span>Subscribe now</span></a></p><h2>The technical side of making art</h2><p>There is a stereotype of artists as strictly right-brained personalities. (Insert your favorite pop-culture image of a painter in a beret and a smock splotched with paint). This trope encourages an image of artists as people who are purely creative, unconcerned with practical matters.</p><p>But in reality, making art requires a significant time investment both terms of tools and learning the peculiarities of a particular medium. To state the obvious, it takes a monumental amount of work to gain mastery at a craft, even if the ultimate purpose of that mastery is creative in nature. When the medium is pencil, an artist gains a mastery of the <a href="https://pencils.com/pages/hb-graphite-grading-scale">HB grading scale</a>, and <a href="https://www.youtube.com/watch?v=2EH95eox9VE">blending</a> on top of the prerequisite background of contrast, perspective and composition. When the medium is code, the artist gains a mastery of writing code and graphics drivers and building shaders.</p><p>Artists are in a pretty competitive market for attention<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. They need to show the audience something interesting or beautiful or intriguing. Even if they make art only for themselves and there&#8217;s an audience of one. The easier a particular kind of art is to make, the more of it is made, and the novelty and originality wears off. Think of photo filters before Instagram: previously you had to have some PhotoShop skills, but once it&#8217;s an app, the filter style becomes a commodity. An artist needs to do something exciting or original<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, rehashing the same thing is boring.</p><p>This treadmill is made even more explicit in the generative art world, where the artist writes code that creates the art. Once you&#8217;ve coded up something that looks interesting, you might naively expect trivially permuting the parameters will give you infinite art. Job&#8217;s done, you can go home: the art creates itself now. But, there&#8217;s inherent similarity between pieces of art using the same underlying code, and viewers pretty quickly catch onto that similarity and tune out.</p><p>Generative artists widely embrace this fact of diminishing returns. You have to keep moving, doing new things, writing new code. This is like exploring a latent space of visual experiences. Regions of the latent space that human brains find interesting are separated from each other by large stretches of things that are boring. It&#8217;s the artist&#8217;s job to travel between those gaps and bring back something cool. The tools they use can help them move more quickly through that space, or eliminate boring regions faster, or simply explore more dimensions. Speed of iteration is kind of a universally good currency here.</p><p>Rust brings a couple of potential advantages as a tool for generative art:</p><ol><li><p>Faster execution means that not only are your graphics primitives executed by a well optimized library, but the top level art is as well. That means more elements can be added to a canvas, more advanced effects can be layered, and more <code>for</code> loop iterations can be executed.</p></li><li><p>The graphics library doesn&#8217;t have to represent an optimization boundary<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. If the generative code is in Rust, the compiler can aggressively optimize the art from top to bottom</p></li></ol><p>Additionally, it seems like a some combination of attributes of Rust are making it particularly fertile ground for cutting edge graphics projects like <a href="https://github.com/gfx-rs/wgpu">wgpu</a>, <a href="https://github.com/vulkano-rs/vulkano">vulkano</a> and <a href="https://github.com/EmbarkStudios/rust-gpu">rust-gpu</a>:</p><ul><li><p>cargo &amp; crates.io make it easy to distribute packages versus the traditional model of creating a shared lib and convincing distro maintainers to distribute it (or trying to add the feature you want to an existing library that is already distributed)</p></li><li><p>programmers who would never have chosen to code in C or C++ are now writing Rust and this naturally brings new ideas and energy into the systems software world (as any influx of new people would do)</p></li><li><p>Sheer enthusiasm for Rust causing people to do ambitious things in it</p></li></ul><p>Having so many high quality choices makes it pretty suitable as a medium for generative art.</p><h2>Interview with MacTuiTui</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://youtu.be/qVJGBEFKWpw" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BJvP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 424w, https://substackcdn.com/image/fetch/$s_!BJvP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 848w, https://substackcdn.com/image/fetch/$s_!BJvP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 1272w, https://substackcdn.com/image/fetch/$s_!BJvP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BJvP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png" width="768" height="768" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:768,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:394250,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://youtu.be/qVJGBEFKWpw&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BJvP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 424w, https://substackcdn.com/image/fetch/$s_!BJvP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 848w, https://substackcdn.com/image/fetch/$s_!BJvP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 1272w, https://substackcdn.com/image/fetch/$s_!BJvP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F19bea608-8954-4754-8d9d-d33a4b2ff3dd_768x768.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Smooth to spiky in half a period</figcaption></figure></div><p>I was excited to talk with Alexis Andr&#233;, a generative artist who creates his art primarily in Rust, using the <a href="https://github.com/nannou-org/nannou">Nannou</a> framework. We talk about his history and how he got into making art with Rust, the iterative process of creating daily art and why Rust is a particularly exciting language for him.</p><p>You can find his dailies on <a href="https://www.instagram.com/mactuitui/">Instagram as MacTuiTui</a> and he posts a wide variety of updates on art on his <a href="https://twitter.com/MacTuitui">Twitter (also MacTuiTui)</a>.</p><p>The transcript below has been lightly edited for length and clarity.</p><p><strong>How did you get into creative, generative coding?</strong></p><p><em>My background is in computer science. I come from the French system, where if you go through the elite course you get into one of the engineering schools and you end up as a general engineer. I decided to actually go to Japan (where I am right now) to get the master&#8217;s, and I did my master&#8217;s in machine learning. Then I switched halfway to get my PhD in computer graphics.</em></p><p><em>That&#8217;s where I started to learn not only about the techniques of rendering graphics, but also about perception, aesthetism, all the rules of color theory. From a technical perspective first, and also from an artistic perspective.</em></p><p><em>And that&#8217;s when I found <a href="https://processing.org/">Processing</a>, because my supervisor was like, &#8220;You need to use Java! Java is going to be the future of graphics!&#8221; and I was like &#8220;I&#8217;m not sure&#8230; but why not.&#8221; That&#8217;s when I found out this new world of generative arts that I was not aware of. I just went through all of the big names at the time. So you have <a href="https://reas.com/">Casey Reas</a>, <a href="https://benfry.com/">Ben Fry</a>, <a href="http://www.complexification.net/gallery/">Jared Tarbell</a>, <a href="http://roberthodgin.com/">Robert Hodgin</a>. That was like 2004-5. Then I went through this habit of tinkering with stuff a lot until it became more and more like a hobby, then it became a job.</em></p><p><em><strong>On learning new technologies</strong></em></p><p><em>In my practice of doing graphics and generative art, I want to be on the technical front end of things, like, being aware of the latest technologies available because it&#8217;s a technical race. So I forced myself to learn new languages periodically. And I actually switched to Scala, and that&#8217;s when I started to do my <a href="https://www.instagram.com/mactuitui/">dailies</a>. I&#8217;ve been doing those for four and a half years, like 1500 days.</em></p><p><em>Then I was really intrigued by the latest GPU technologies where you had <a href="https://en.wikipedia.org/wiki/Vulkan_(API)">Vulkan</a>, <a href="https://developer.apple.com/metal/">Metal</a> and <a href="https://www.nvidia.com/en-us/geforce/technologies/dx12/">DirectX 12</a> that were coming out. The way Processing was was designed at the time, it was still stuck in the <a href="https://en.wikipedia.org/wiki/OpenGL">OpenGL</a> way of doing graphics. That was not the way forward.</em></p><p><em>I was looking for a way to upgrade to Vulkan first, and that&#8217;s when I found Nannou. That was one of the few frameworks that were actually pushing the way forward, breaking things along the way if needed, but using the latest technologies. I went through a lot of version with them to maybe being the heaviest user of the framework.</em></p><p><em>Finally, I can hear my GPU working, where previously it was mostly CPU bound. It&#8217;s really interesting to get to the point where the computer is giving up. That&#8217;s really rewarding in a way where you can get like a GPU crash because the shader went into a weird loop.</em></p><p><strong>Did you learn about GPU shaders in school or is that something you&#8217;ve taught yourself since then?</strong></p><p><em>I was doing shaders at the very beginning of the technology, like I had been doing <a href="https://en.wikipedia.org/wiki/General-purpose_computing_on_graphics_processing_units">GPGPU</a> stuff in 2005-6. In my lab, we were doing oil painting simulation and that was mostly shaders. But I&#8217;m not really a shader guy. If I look at what people are doing with shaders right now&#8230; I&#8217;m not there. I know the basics and I was there at the beginning, but it moves so fast that I&#8217;m still playing.</em></p><p><em>That&#8217;s why I&#8217;m interested in having access to those technologies in a nice framework so that I can manage to push forward.</em></p><p><strong>I know Nannou does WebGPU rendering, is most of your work rendered as a video, or do you render it all on the browser side?</strong></p><p><em>No, the whole <a href="https://github.com/nannou-org/nannou/issues/475">compile to Web Assembly</a> is not ready yet. That&#8217;s the end goal. Personally, I would really like to reach the point where I can just put the code for everyone to run in their browsers. That&#8217;s part of the appeal of using Nannou because eventually <a href="https://en.wikipedia.org/wiki/WebGPU">WebGPU</a> will be available for everyone to use in the browser. Rust is the way forward for this.</em></p><p><em>In the next few months we&#8217;ll reach the point where I can just push everything that I do online and people can interact with it. Right now, it&#8217;s rendering as a native application on my computer. I export each frame and then I combine them as a video and push the video to social media, so it&#8217;s a two step process.</em></p><p><em>But it also allows me to do really intensive stuff where I don&#8217;t care about it being realtime as much because it&#8217;ll be compiled as a video afterwards. So I can cheat a little bit by making really intensive computation that looks crazy but isn&#8217;t real time.</em></p><p><strong>Nannou has added a few features just based on your requests, can you talk about those?</strong></p><p><em>The first one that I asked for, when I was doing my daily animations, I needed a way to save the current frame to a file so I can combine them. So for the first few months, I had a custom build that was just for me, where the screenshot feature was available until they managed to add it to the library.</em></p><p><em>The second one was using blending. Blending is how you mix colors on the screen. It&#8217;s really interesting to see how people have been doing it wrong in the past because of the limitations of OpenGL and the way it was done for ages before. So if you think about using colors as a 24-bit number, so we have 256 levels of color per channel, that&#8217;s not enough. We get <a href="https://en.wikipedia.org/wiki/Colour_banding">banding</a>. If we want to mix color together, we don&#8217;t have enough precision.</em></p><p><em>What Nannou has been able to do with the help of WebGPU, is that we have floats, real floats, for each color channel. So we can mix colors at a level that no other framework is able to do. We can reach truly bright colors and truly dark colors at the same time with the whole spectrum in between.</em></p><p><em>The team behind Nannou has been really helpful on a day-to-day basis. There were a couple of days where they really went down with me, documenting some features just to help me manage to complete the daily in time. So <a href="https://github.com/mitchmindtree">Mitch</a>, <a href="https://github.com/JoshuaBatty">Josh Batty</a>, <a href="https://github.com/freesig">Tom</a> thanks a lot for all the hard work!</em></p><p><strong>One of the benefits Nannou mentions is that the language used by the framework is the same one the framework is built in. Have you found that that&#8217;s been a useful property?</strong></p><p><em>The way I&#8217;m using the framework is pretty much still, from the Rust perspective, pretty much a beginner level. I&#8217;ve contributed a few examples to show what the framework is able to do, but I&#8217;m pretty sure any experienced Rust programmer will come and say &#8220;Oh, this is dumb.&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a></em></p><p><em>But to be fair, creative coding is more about: &#8220;You take one circle, it&#8217;s fine. You take one thousand circles, then it&#8217;s becoming more interesting. Then you take ten thousand circles and make them move around.&#8221; It&#8217;s just a couple of forms and you have something that looks nice, and it&#8217;s a lot about the details about how you make them move and interact.</em></p><p><em>So, it&#8217;s not really about the language, because I&#8217;m not developing the framework, I&#8217;m just using the features that are available. I&#8217;d like to be able to contribute more, because I think I owe them that.</em></p><p><em>I still find Rust sometimes really challenging. I have not taken the time to get comfortable in terms of the advanced features of the language. Every time I see an <a href="https://doc.rust-lang.org/std/sync/struct.Arc.html"><code>Arc</code></a>, I&#8217;m like &#8220;Oh, that&#8217;s not for me yet.&#8221; Like there are a few points of the language design I&#8217;m not comfortable using. So I just worked my way around and for me that&#8217;s enough. I should do more, but from the perspective of a heavy user, that&#8217;s where I am.</em></p><p><strong>Can you talk a little bit about your experience with Rust in general? Do you regularly run into issues where you&#8217;re like &#8220;Okay, this is annoying because it&#8217;s in Rust?&#8221;</strong></p><p><em>In the first six months, yes all the time. Especially the way Nannou has been designed. You have the <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">model-view-controller</a> pattern, so when you&#8217;re drawing something you <a href="https://guide.nannou.cc/tutorials/basics/anatomy-of-a-nannou-app.html#view---presenting-the-model-to-a-window">cannot mutate the data</a>. From the Processing way of thinking, you can do it whenever you want, wherever you want. Sometimes there is stuff that I&#8217;d like to do, where it makes sense to draw as you&#8217;re mutating the model.</em></p><p><em>Also, the thing that I&#8217;m not sure I&#8217;m doing right, even right now, is that when you have a list of things and you want to mutate them two elements at the same time. I just use <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut">split_at_mut</a>.</em></p><p><em>I have a few tricks that I&#8217;m sure are wrong, but right now I think I&#8217;ve reached a point where I think before deciding what I&#8217;m going to do. So, I know that I will be able to do this with my skills in Rust. I don&#8217;t hit any compiler errors right now, because I&#8217;ve reached the point where I&#8217;m fluent enough to do what I want to do.</em></p><p><strong>Are there any projects you&#8217;ve done that stick out in your mind as being really difficult from a technical perspective?</strong></p><p><em>I think the hardest thing was when I tried to do real-time path tracing 2d simulation. There was a time of, maybe last summer where I had those really crazy effects where lights were bouncing around walls and shining.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://youtu.be/aBfuo7fQZ-U" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pfbw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 424w, https://substackcdn.com/image/fetch/$s_!Pfbw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 848w, https://substackcdn.com/image/fetch/$s_!Pfbw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 1272w, https://substackcdn.com/image/fetch/$s_!Pfbw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pfbw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png" width="1298" height="1302" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1302,&quot;width&quot;:1298,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:856588,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://youtu.be/aBfuo7fQZ-U&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Pfbw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 424w, https://substackcdn.com/image/fetch/$s_!Pfbw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 848w, https://substackcdn.com/image/fetch/$s_!Pfbw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 1272w, https://substackcdn.com/image/fetch/$s_!Pfbw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4b4affa-a699-42b1-bdbd-0a8185d9037a_1298x1302.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>That was the results of getting to know <a href="https://sotrh.github.io/learn-wgpu/beginner/tutorial3-pipeline/">compute shaders in WebGPU</a>. The whole stuff was like maybe 1000 lines of code just to prepare for the rendering. Then finally just inputting the data and making the stuff move was pretty easy. But it took me maybe a month of incrementally adding the next block to the puzzle so that I know that eventually I would be able to do that.</em></p><p><em>And when I was was able to do that I just abused it for two months. Like, I spent one month building the tech, I&#8217;m going to milk it for a long time!</em></p><p><em>That was really hard, but I learned so much about compute shaders, render pipelines, how to time the GPU to cache so that all the data is moving in the right way at the right time. So that, eventually, it works in almost real time.</em></p><p><em>That&#8217;s what I was talking about getting the GPU on their knees. That was the part where I managed to crust the system a lot. When you do compute shaders, you&#8217;re really free to do whatever you want. And when the GPU is not responding, the OS is like &#8220;I don&#8217;t know what is happening&#8221;, but it needs to just reset the driver, and you&#8217;re stuck in the middle of a loop where your computer is showing nothing&#8230; you&#8217;re hoping that you might come back&#8230;</em></p><p><strong>Have you found compile times to be much of an issue?</strong></p><p><em>Not that much. Right now, my compile time is like five seconds for the dailies. I use Vim, I have the LSP plugin, so the compiler will tell me any error before I try to compile. When I write the code, it&#8217;s almost too fast, the feedback I get from the computer.</em></p><p><em>From this perspective, I&#8217;m really happy with my workflow right now. When the compiler will not complain any more: I will get the results I want. Then it&#8217;s thinking about the algorithm itself, it&#8217;s not about the way to express it in code. So personally I&#8217;m super happy with the compile time and workflow.</em></p><p><strong>I saw your <a href="https://githubuniverse.com/Nannou-creative-coding-with-Rust/">GitHub Universe stream</a>, and I was wondering whether that was a super polished presentation or whether that&#8217;s representative of your daily coding flow.</strong></p><p><em>If you do daily times like I do, any bit of optimization is worth taking the time to master. It&#8217;s about finding the set of tools that will allow me to be efficient and not spend a lot of time in the tooling because I don&#8217;t have that time every day.</em></p><p><em>I also code a lot for work. So Vim is a skill that I don&#8217;t see a disadvantage of learning to use at a higher level. A few years ago, before <a href="https://microsoft.github.io/language-server-protocol/">LSP</a> was the norm, I would say that maybe using Visual Studio might be a better choice, just to get the integration with the compiler. But right now with the new plugins and everything it makes absolutely no difference if you use VSCode or Vim.</em></p><p><em>I put Vim mode in all my other software. I&#8217;m so used to thinking in modes I do all my reports for work in Vim.</em></p><p><strong>Have you used Rust for anything other than creative projects?</strong></p><p><em>I&#8217;ve been using Rust and Nannou in my work as well. I&#8217;ve been building tools to design murals, to design tiles, to design walls. I&#8217;ve been doing a lot with small robots for my company and I&#8217;ve built a toolchain around them with Rust and Nannou. I&#8217;m actually using that hardware as an interface for my dailies, so that I can change all the parameters with them.</em></p><p><em>So yeah Rust right now is my default choice. I don&#8217;t think I can use any other language. I worked a lot in Java but that was 20 years ago. I don&#8217;t know any C or C++ to the point where it would make sense to consider them.</em></p><p><em>I also like cargo and the whole ecosystem behind Rust. It just runs. The whole process of making it run on a new system is really straightforward. I have yet to encounter an issue where I was not able to just take a computer, install Rust, install cargo, cargo run and then it runs. This has been so easy in terms of deployment.</em></p><p><em>Recently, I&#8217;ve done JavaScript and Rust. JavaScript when it has to run on the web. I&#8217;m hoping once WebAssembly is available in a few months that I can just switch everything to Rust. For me, there is no other choice right now.</em></p><p><strong>Is there anything else you&#8217;d like to mention?</strong></p><p><em>I think if anyone is interested in the concept of Rust and trying out something new, creative coding is something that is really satisfying. You write something, and you get a nice picture. In terms of not writing another Hello World tutorial, making a nice circle on the screen is a little more interesting in terms of getting to know the language. It could be a really good introduction.</em></p><p><em>Like, if you look at how I designed my presentation for GitHub Universe, I introduce a lot of concepts in an incremental manner. You just start with getting cargo to create a new binary to make it run. All the steps that you need to make your own projects, well, you can do them with Nannou.</em></p><p><em>And you get a nice picture as well which could be more rewarding.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://youtu.be/6xBBivTN-eE" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!97U_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 424w, https://substackcdn.com/image/fetch/$s_!97U_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 848w, https://substackcdn.com/image/fetch/$s_!97U_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 1272w, https://substackcdn.com/image/fetch/$s_!97U_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!97U_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png" width="762" height="762" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:762,&quot;width&quot;:762,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:838779,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://youtu.be/6xBBivTN-eE&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!97U_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 424w, https://substackcdn.com/image/fetch/$s_!97U_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 848w, https://substackcdn.com/image/fetch/$s_!97U_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 1272w, https://substackcdn.com/image/fetch/$s_!97U_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69e7e78-cbcf-486f-9f2e-ee0a798b54c2_762x762.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Of course, I might get lost along the way</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/p/making-generative-art-with-rust/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/p/making-generative-art-with-rust/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I&#8217;m ignoring the fine art world. There is much more going on there with reputation, status and luxury economics (and maybe <a href="https://www.cnn.com/2020/07/29/business/art-money-laundering-sanctions-senate/index.html">money laundering</a>?) than are really relevant to this blog</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>As with every blog, you can mentally prefix all sentences with &#8220;In my opinion&#8230;&#8221;</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Assuming <a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#lto">LTO</a> is enabled. Also, apparently Rust has <a href="https://blog.llvm.org/2019/09/closing-gap-cross-language-lto-between.html">cross-language LTO</a>? That&#8217;s kind of nuts</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>I very much disagree with him here!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Rust Notebooks with Evcxr]]></title><description><![CDATA[Why code notebooks are better than the shell, and an interview with David Lattimore, the creator of the Rust Jupyter kernel]]></description><link>https://blog.abor.dev/p/evcxr</link><guid isPermaLink="false">https://blog.abor.dev/p/evcxr</guid><dc:creator><![CDATA[Josh Kuhn]]></dc:creator><pubDate>Fri, 23 Apr 2021 17:49:08 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/fb7b869f-d508-4cb4-963c-a1ad5459873e_258x237.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sometimes things are invented in the wrong order. There&#8217;s no technological limitation or breakthrough that precludes a particular invention, it just so happens by historical accident that an alternate technology is invented and becomes widespread before a better idea is struck upon.</p><p>For example, <a href="https://en.wikipedia.org/wiki/Marine_chronometer">marine chronometers</a> are a very complicated and hard to engineer way to keep time on the ocean<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> used in the 18th and 19th centuries. In the 20th century, ships switched to using <a href="https://en.wikipedia.org/wiki/Time_signal">radio time signals</a>. Radio signals are very easy to generate, and quartz clocks are a very accurate way to keep time. Both are much easier to build than a marine chronometer and they&#8217;re more accurate and robust to failure. We just&#8230; didn&#8217;t think of it first<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>Something like this happened with code notebooks<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. REPLs (including shells like Bash) were invented and got popular with the rise of Unix and scripting languages. But the basic idea of a code notebook could have been invented any time. The core technology needed for a code notebook is the same as for a shell: you need a way to execute code in the language, maintain a context, and display the output.</p><p>As a consequence of inventing code notebooks embarrassingly late, it feels natural to describe them as &#8220;like a REPL, but with extra features like displaying images&#8221;. Instead we should be describing REPLs, including shells, as &#8220;kind of like a notebook, but worse and harder to use&#8221;. It&#8217;s hard to look at someone spamming &#11014;&#65039; and <code>Ctrl+R</code> in a shell and not think they would have benefited from using a code notebook where you can simply edit previous cells.</p><p>Notebooks are usually associated with data science work, but this is only because the shell doesn&#8217;t provide good visualization capabilities<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>. Developers on *nix systems learn to use the shell as an interface to all kinds of system tasks, so they tend to be comfortable with the command line. But data scientists generally don&#8217;t get this extensive shell indoctrination and Jupyter is readily available and more than capable. We can take from the fact that data scientists are not clamoring to do data science from the terminal as some evidence that, in fact, code notebooks are the more general solution.</p><p>And as long as we&#8217;re replacing the shell with a notebook, we might as well replace the language of the shell with Rust.</p><h2>Quick overview of Evcxr</h2><p><a href="https://github.com/google/evcxr">Evcxr</a> is a Jupyter kernel for Rust. It makes iterative, one-off, and task-oriented coding much more enjoyable in Rust. It&#8217;s not that you can&#8217;t do iterative duct-tape-and-hairpin coding with cargo and an IDE, it&#8217;s just that it&#8217;s so much more <em>ceremony</em>.</p><p>With Evcxr, you can add dependencies from crates.io, and use them immediately:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zJ3F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zJ3F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 424w, https://substackcdn.com/image/fetch/$s_!zJ3F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 848w, https://substackcdn.com/image/fetch/$s_!zJ3F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 1272w, https://substackcdn.com/image/fetch/$s_!zJ3F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zJ3F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png" width="1402" height="227" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:227,&quot;width&quot;:1402,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:48256,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zJ3F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 424w, https://substackcdn.com/image/fetch/$s_!zJ3F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 848w, https://substackcdn.com/image/fetch/$s_!zJ3F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 1272w, https://substackcdn.com/image/fetch/$s_!zJ3F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5d9df231-1a42-4625-9e09-94f81ab59d5a_1402x227.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This interweaving of what would normally go into <code>Cargo.toml</code> with the source code itself is exactly the kind of thing that&#8217;s great for iteratively solving a problem, but which most tooling avoids because it&#8217;s not very maintainable. That&#8217;s ok though: notebooks are not for maintaining. They&#8217;re a place to solve a particular problem, and if you&#8217;re feeling especially motivated and energetic, a place to document what you learned. </p><p>You can also do async and ? without any ceremony in a cell. It will wrap your code with the necessary invocations before running it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Yyzl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Yyzl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 424w, https://substackcdn.com/image/fetch/$s_!Yyzl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 848w, https://substackcdn.com/image/fetch/$s_!Yyzl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 1272w, https://substackcdn.com/image/fetch/$s_!Yyzl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Yyzl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png" width="1261" height="316" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:316,&quot;width&quot;:1261,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57553,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Yyzl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 424w, https://substackcdn.com/image/fetch/$s_!Yyzl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 848w, https://substackcdn.com/image/fetch/$s_!Yyzl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 1272w, https://substackcdn.com/image/fetch/$s_!Yyzl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9cbc604-ddad-46e9-90ed-fd3996bebb6c_1261x316.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Evcxr is really promising technology, but it has a few limitations. While async works, it looks like rustc made some changes to dynamic libraries that <a href="https://github.com/rust-lang/rust/issues/82972">don&#8217;t interact well</a> with Evcxr, so async is currently stuck on pre-1.0 tokio. The inline type checking was a little hit or miss for me as well. Sometimes it triggered, sometimes it didn&#8217;t. This may be a Jupyter issue. I would very much like to get autocomplete in cells.</p><p>Long term, because Evcxr is using rust-analyzer internally, it&#8217;s poised to benefit from the autocompletion and code fixes from that project. One of the reasons common shell commands have very short names (e.g. <code>ls</code>, <code>mv</code>, <code>git</code>) is because when you&#8217;re solving something, typing speed is really important. Good autocomplete mostly eliminates that advantage, and in return hands us back the ability to use more than three letters in our function names.</p><p>Overall, I&#8217;m very excited about what Evcxr unlocks.</p><h2>Interview with David Lattimore</h2><p>I chatted briefly with David, the creator of Evcxr who was kind enough to answer my questions. We talk about the internals of Evcxr, features he&#8217;d like to add, some of his work on structural search and replace in rust-analyzer, and what he&#8217;s excited about in the Rust ecosystem.</p><p>The following is a transcript of our conversation edited for length and clarity.</p><p><strong>So I guess the first question I have is: how do you pronounce the project name?</strong></p><p>I pronounce it &#8220;e-vix-er&#8221;. Whenever Evcxr is brought up on Reddit or something like that, someone will be like &#8220;It's a terrible name!&#8221; or like &#8220;I can never remember the name!&#8221;. It's quite searchable, which I guess is part of the motivation. You're not going to confuse it for something else or get results for something else.</p><p>But unfortunately, it's very difficult to remember and very difficult to work out how to pronounce.</p><p><strong>Could you talk a little bit about what you worked on previous to Evcxr, and what kind of led you up to creating the project?</strong></p><p>At the time I'd started it, I'd been playing with writing a linker,<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a> so I'd been playing in that space of loading and dealing with object files and shared objects and those kinds of things. And it just kind of occurred to me that it would be reasonably easy (or I thought it would be reasonably easy) to make a REPL like-thing just by loading shared objects and running the code.</p><p>It was reasonably quick to get something basic up and running. As always with these things the devil is always in the detail. It's a continuously evolving project to add the many subtle features and make different things work well.</p><p><strong>So it started out as a REPL and you added the Jupyter kernel on afterwards?</strong></p><p>Yes, although I added the Jupyter kernel before I released. I wrote the REPL and then I thought, &#8220;Well my wife is a data scientist, so she uses a Jupyter notebook quite a bit. That could be kind of fun to try and make a Jupyter kernel as well"</p><p>So I spent an extra couple of weeks and make a basic Jupyter kernel before I released.</p><p><strong>Had you used Jupyter much previously yourself?</strong></p><p>I'd never really used it myself. I'd just seen her using it and I thought it looked kinda cool.</p><p><strong>It looks like you switched the project from using <a href="https://crates.io/crates/syn">syn</a> to using <a href="https://github.com/rust-analyzer/rust-analyzer">rust-analyzer</a>. Can you talk about how that works?</strong></p><p>Yeah sure, I <a href="https://github.com/google/evcxr/commit/b82b7eabb9fe5f4fb7de42c686bd52148ad42a24">switched to using rust-analyzer about six months ago</a>.</p><p>Prior to that I would generate the code, and then ask the Rust compiler to compile it, and then look at what the errors were. I assumed that all the variables were of type <code>String</code>, and I would look at the errors were produced. The Rust compiler can happily format its output as JSON, so you get like a JSON representation of the errors and you just pull out the error message for a particular variable and see it says, you know "found this type, expected that type".</p><p>That worked for quite a few years, but then <a href="https://github.com/rust-lang/rust/pull/49546/">recently they changed the messages so that they no longer included the fully qualified type</a>. So instead of saying, you know, <code>std::collections::HashMap</code> or something like that it would just say <code>HashMap.</code> And without the fully qualified type <a href="https://github.com/google/evcxr/issues/138">I couldn't use those types anymore</a>, they just weren't sufficient.</p><p>So, I switched to using rust-analyzer. If rust-analyzer can't determine the type, Evcxr will still fall back to using the compiler messages. The only reason I've got that there is because rust-analyzer doesn't deal with fixed-sized array types. Like <a href="https://github.com/rust-analyzer/rust-analyzer/issues/7432">it doesn't tell you the size of the array in the type that rust-analyzer infers</a>, so if you have like:</p><pre><code>let array_of_ints = [0; 5];</code></pre><p>rust-analyzer's type will just say:</p><pre><code>[i32; _]</code></pre><p>I can't use that, so for those particular cases I still fall back to using the compiler error messages to determine the types.</p><p>I would like to get rid of that code because it's... it's a bit ugly. It's a bit of a hack. But yeah for the most part I'm using rust-analyzer. I'm also not using syn any more, so I've switched entirely to using rust-analyzer to do the parsing.</p><p><strong>How do you find using rust-analyzer as a library? I know it's broken into crates so it's theoretically usable as a library, but you're actually using it in anger, so what's that been like?</strong></p><p>It's pretty good. Probably my biggest complaint would be that it's quite big and so it takes a while to compile. Certainly my continuous integration slowed down quite a lot when I pulled in rust-analyzer because now every time it runs it has to build all of rust-analyzer which takes a while.</p><p>An alternative way that I could have integrated that I didn't consider at the time was to actually pull in the rust-analyzer binary and talk to it using the <a href="https://microsoft.github.io/language-server-protocol/">language server protocol</a>, instead of using it as a library. Obviously, that would have been better from a compilation time perspective, but I just wasn't sure whether I'd have access to everything I needed. So I didn't end up going that route.</p><p><strong>What kind of features do you want to add to Evcxr that you feel are missing?</strong></p><p>One feature that I started looking to try and add a while back, but I just haven&#8217;t had time recently, is allowing code that runs in a Jupyter notebook to interact with the notebook process. Allowing some way for JavaScript code that runs in the browser, to communicate with some Rust code that runs in a library.</p><p>Like maybe in a crate, where you pull in a crate that, you know, creates a graph or something like that, and that code then talks to the JavaScript code running in the browser. So you can have bidirectional communication going backwards and forwards allowing an interactive thing to be displayed in the notebook.</p><p><strong>Like a slider widget, something like that?</strong></p><p>Exactly, yep. So I started working on that I think I got some of the basic stuff working. I think I, I can't remember where I was up to with it but I remember I had issues with Mac. Like the changes I'd made when I pushed them, the tests failed on Mac.</p><p>It's probably because I didn't have access to a Mac, so the only way I can test these changes is like: put some print statements in, push to CI, and then wait for Travis to run Mac, which takes like half an hour or an hour. And then, you know, see what the values the print statements are. It can make a really frustrating and slow testing experience.</p><p>I should probably put a call out just to ask if anyone with a Mac wants to come and help. It would make things much easier!</p><p><strong>It's currently pre 1.0, what are your criteria for making a 1.0 release?</strong></p><p>You know, I haven't really given too much thought to 1.0. I guess, so, Evcxr itself is a library, which is then used by the Jupyter notebook and the REPL. And I make breaking changes to the API of that library moderately often. Just because it's convenient, and because the only two users of the library are in the same repository.</p><p>So I guess I'd need to think about how I want to treat it with regards to <a href="https://semver.org/">semver</a> there. Maybe if I just kept the library pre-1.0, but made the notebook and the kernel be 1.0, then I could get away with it. Because I'd still like to be able to make breaking changes to the library.</p><p>The API of the library is very <em>not</em> stable.</p><p><strong>It looks like after <a href="https://github.com/kurtlawrence/papyrus">Papyrus</a> and <a href="https://github.com/murarth/rusti">Rusti</a> stopped being maintained, Evcxr seems to be the only Rust REPL that has any recent commits to it. How do you feel about being the sole Rust REPL at this point?</strong></p><p><em>[It turns out I was wrong about this. After our conversation David pointed out <a href="https://github.com/sigmaSd/IRust">IRust</a>, which is a new Rust REPL that&#8217;s being actively developed]</em></p><p>At time I wrote Evcxr, there was only one other REPL, which was rusti. I think at the time it didn't say it wasn't maintained, but it was running on an old version of nightly from 2016. I think the issue there was that they were using some compiler internals, and those compiler internals got removed, so there was no way they could move forward to allow a new version.</p><p>I think it was using some compiler internals to get access to the LLVM IR or something like that. And then they'll be using LLVM to JIT it or something like that. It worked completely different to the way Evcxr works.</p><p>But there was no equivalent API provided, because the compiler just stopped... doing that.</p><p><strong>Is this your main Rust project?</strong></p><p>The original Rust project that I worked on and released was a thing called <a href="https://github.com/google/rerast">Rerast</a>. Which was a structural search and replace tool. So it searched for Rust code, and replaced it based on a parse tree pattern. It used a lot of compiler internals and was nightly only. It was a bit of a pain to maintain and had a relatively low number of users.</p><p>But it broke very often, because the compiler internals were always changing. Because I depended on almost the entire surface area of the AST. Any time they changed the AST, my builds would break and I had to go fix it. So we had like fifty build fixes in one year, so round about one per week.</p><p>So eventually, once rust-analyzer got good enough, I helped out there. There was already some support for structural search and replace in rust-analyzer, and <a href="https://github.com/rust-analyzer/rust-analyzer/issues/3186#issuecomment-644069324">I built that up to close enough to feature parity to what I had in Rerast</a>, and then deprecated Rerast.</p><p><strong>So you're working on the structural search and replace in rust-analyzer itself?</strong></p><p>Yeah I've done a lot of work on that. There's a lot more I'd like to do there as well, but yeah, I haven't really had time lately.</p><p>What I'd really like to see there would be some way for library authors to be able to make a change like they deprecate some API, and they put some annotations on the API that they're deprecating to provide a structural search and replace rule to allow you to automatically transition to the new API.</p><p>Then have the IDE automatically suggest that for you. Kind of how the compiler can make suggestions and the IDE can apply them. But this would be something driven by the library authors, not by the compiler team. So I'd like to see something like that, but I really haven't had time to drive that.</p><p><strong>I'm curious if you have any places where you think Rust is particularly poorly applicable. Areas where Rust is maybe never going to be a good solution. Do you have any opinions on that?</strong></p><p>I don't think it's a super hard language to learn. But I don't think it would be suitable as like a first language for kids, for example. For them you really want something that's simpler. I don't know whether Python is the right thing for kids, or scratch or something like that.</p><p>I'm not about to teach my kids Rust!</p><p>I guess in terms of industries, I think it probably could work pretty well in most cases. Certain kinds of problems can be a little annoying to try and do in Rust: graphs and things like that, that can be a bit annoying. Although there are ways to manage it, you've just got to structure your code a bit differently.</p><p>Often the ways you structure it end up being quite nice. So maybe it's not an issue. I found when I've done graphs in the past, just assigning integer ids to things, and things work out pretty well. Don't use pointers.</p><p>Nothing in particular comes to mind.</p><p><strong>What are you most excited about in terms of Rust?</strong></p><p>I've recently become quite interested in embedded programming in Rust. Mostly I'm excited to see Rust growing. And just seeing it continue to become bigger and better and more ergonomic and better tools and better libraries. Because that really does start to fill in the gaps where maybe it was a good language, but didn't have good libraries, but once you fill in the libraries then, there's really no reason not to use it.</p><p><strong>I don&#8217;t know much about the embedded space. Is that growing a lot now in terms of usage?</strong></p><p>I think it's a lot better than it was a few years ago. Like, I remember someone saying four or five years ago that there was pretty much one person working on embedded Rust. It probably wasn't true, but like there was one person really driving it. Whereas now, it feels like there's a lot of people you can point to where they're very clearly big in the embedded space. And you've got companies like <a href="https://ferrous-systems.com/">Ferrous Systems</a> doing great work in the embedded space.</p><p>It feels like there's quite a few more people working and although there's still bits and pieces missing it's a pretty nice experience and works reasonably well. At least depending on... It depends on what you're trying to use and what you're trying to do with it.</p><p>I don't know if you've seen <a href="https://knurling.ferrous-systems.com/">Knurling</a>. They've been doing a lot of <a href="https://knurling.ferrous-systems.com/sessions/">Knurling sessions</a> where they'll announce they're going to build, like, a CO2 sensor or something like that. They give you the part list of what you have to buy, and you order those online somewhere and then as the session goes on they release information about how to do different things with it. You then build this sensor and program it.</p><p>They don't provide <em>all</em> the details. I assume they provide code samples, but like the idea is that you write the code. So you're learning how to do it. There's other people who are learning as well, so if you're having troubles you can talk to other people to see what they've done.</p><p>They also make a bunch of tools, so there's a bunch of crates and utilities they've released to make it easier to do embedded Rust development. Things like <a href="https://github.com/knurling-rs/probe-run">probe-run</a> where you can just type <code>cargo run</code> and it will compile your code and then run it on the device. And any log statements that you have in your code are on the device and just show up in your terminal. So it's like you're running it on the local machine but in actual fact it's running on a device you've got plugged in over USB.</p><p>If you <code>Ctrl+C</code> you get a stack dump of where it was on the device. It's quite a nice development experience in that regard. They've helped build out some of that stuff along with others in the community.</p><p><strong>Thanks for taking the time to talk with me, is there anything you want to plug?</strong></p><p>I need to figure out how to get Evcxr showing up in the first results when you search for &#8220;rust repl&#8221;. It&#8217;s at least on the first page, but that&#8217;s still not great given it&#8217;s been around for a few years now. I don&#8217;t know how to fix that kind of thing.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/p/evcxr/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/p/evcxr/comments"><span>Leave a comment</span></a></p><h2>Upcoming posts</h2><p>I&#8217;ve got an interview with a generative artist that creates his works primarily in Rust, along with the primary developer of Seed, a frontend Rust web framework. Those should be out in the next couple of weeks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.abor.dev/publish/post/https://blog.abor.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.abor.dev/publish/post/https://blog.abor.dev/subscribe?"><span>Subscribe</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>With accurate timekeeping you can determine your ship&#8217;s longitude.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Many more examples like this can be found in Ryan North&#8217;s book <a href="https://www.howtoinventeverything.com/">How to Invent Everything</a></p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I&#8217;m calling them generically &#8220;code notebooks&#8221; here to indicate the general concept <a href="https://paulromer.net/jupyter-mathematica-and-the-future-of-the-research-paper/">pioneered by Mathematica</a> and popularized by <a href="https://jupyter.org/">Jupyter</a>. But if you want to mentally translate that to &#8220;Jupyter notebook&#8221; in your head, feel free.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Various attempts at displaying images in a terminal emulator are out there. I personally use <a href="https://sw.kovidgoyal.net/kitty/">Kitty</a> myself, which supports images, but it&#8217;s nothing like a standard or something that people are seriously targeting as a visualization platform. It&#8217;s cool though, don&#8217;t get me wrong.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p><a href="https://github.com/google/evcxr/blob/master/evcxr/HOW_IT_WORKS.md">Evcxr works by compiling each cell to an .so file</a> and having the main notebook process dynamically load them and run the contained function.</p></div></div>]]></content:encoded></item></channel></rss>