<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<author>
<name>Erika Rowland</name>
</author>
<id>https://erikarow.land/combined.xml</id>
<title>Combined Feed</title>
<updated>2024-07-27T00:00:00+00:00</updated>

<entry>
<content type="html">
&lt;section id=&quot;Using-use-in-Gleam&quot;&gt;
&lt;h1&gt;Using &lt;code&gt;use&lt;/code&gt; in Gleam&lt;/h1&gt;
&lt;p&gt;Recently, a colleague checked out Gleam&amp;rsquo;s &lt;a href=&quot;https://tour.gleam.run&quot;&gt;language tour&lt;/a&gt;. They liked what they saw, but they were confused by Gleam&amp;rsquo;s &lt;code&gt;use&lt;/code&gt; syntax. I like Gleam&amp;rsquo;s syntax a lot&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I even wrote an article about &lt;a href=&quot;/notes/gleam-syntax&quot;&gt;Gleam&amp;rsquo;s syntax&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;, but I was also confused by &lt;code&gt;use&lt;/code&gt; when I first encountered it. Here&amp;rsquo;s how I use &lt;code&gt;use&lt;/code&gt;:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;code&gt;use&lt;/code&gt; expression was introduced in &lt;a href=&quot;https://gleam.run/news/v0.25-introducing-use-expressions/&quot;&gt;Gleam v0.25&lt;/a&gt;, as a more general replacement for the &lt;code&gt;try&lt;/code&gt; keyword that preceded it.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;What-is-use-anyway&quot;&gt;
&lt;h2&gt;What is &lt;code&gt;use&lt;/code&gt; anyway?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://tour.gleam.run/advanced-features/use/&quot;&gt;&lt;code&gt;use&lt;/code&gt;&lt;/a&gt; is a Gleam expression that allows me to write code that uses a callback&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;ve heard debate over whether a function argument to a higher order function is &lt;em&gt;always&lt;/em&gt; a callback, but &lt;a href=&quot;https://tour.gleam.run/advanced-features/use/&quot;&gt;the language tour&lt;/a&gt; for Gleam uses &amp;ldquo;callback function&amp;rdquo;, so I&amp;rsquo;ve used callback here.&lt;/span&gt;&lt;/span&gt; function in an unindented style. Specifically, for functions whose last argument is a callback function. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/list

fn catify_without_use(strings: List(String)) -&amp;gt; List(String) {
  list.map(strings, fn(string) {
    string &amp;lt;&amp;gt; &quot; cat&quot;
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I take a list of strings and append &lt;code&gt;&quot; cat&quot;&lt;/code&gt; to the end of each of them. &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html#map&quot;&gt;&lt;code&gt;list.map&lt;/code&gt;&lt;/a&gt; takes a list as the first argument, and a callback function that takes a list element and returns a new list element. Here&amp;rsquo;s what that same function looks like with a &lt;code&gt;use&lt;/code&gt; expression:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/list

fn catify_with_use(strings: List(String)) -&amp;gt; List(String) {
  use string &amp;lt;- list.map(strings)
  string &amp;lt;&amp;gt; &quot; cat&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the &lt;code&gt;use&lt;/code&gt; expression has done three things:&lt;/p&gt;
&lt;p&gt;First, we&amp;rsquo;ve moved the arguments for the callback function to the left of the arrow. &lt;code&gt;fn(string)&lt;/code&gt; becomes &lt;code&gt;use string &amp;lt;-&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The name &lt;code&gt;string&lt;/code&gt; is an identifier chosen by me, it could just as easily be &lt;code&gt;use to_be_catted &amp;lt;- ...&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Second, we&amp;rsquo;ve changed &lt;code&gt;list.map&lt;/code&gt; into a function that takes one less argument than it usually does. It&amp;rsquo;s now &lt;code&gt;list.map(strings)&lt;/code&gt; as though it only took one argument. &lt;code&gt;list.map&lt;/code&gt; still takes two arguments, but &lt;code&gt;use&lt;/code&gt; has changed how we write that second argument.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This aspect of &lt;code&gt;use&lt;/code&gt; makes it easier to see what the non callback arguments of a &lt;code&gt;use&lt;/code&gt;d function are, since the callback is often the bulkiest part of the outer function call signature.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;code&gt;use&lt;/code&gt; statement has exactly one identifier, because that&amp;rsquo;s how many arguments &lt;code&gt;list.map&lt;/code&gt;&amp;rsquo;s callback function needs, see &lt;a href=&quot;#A-note-on-use-arguments&quot;&gt;this note&lt;/a&gt; for more examples.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Third, the body of the callback function is now below the line of the &lt;code&gt;use&lt;/code&gt; expression, indented in line with the &lt;code&gt;use&lt;/code&gt; expression. Everything below the &lt;code&gt;use&lt;/code&gt; expression until the end of &lt;code&gt;catify_with_use&lt;/code&gt; becomes the body for the callback function.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;That is, everything in the same &lt;em&gt;block&lt;/em&gt; as the &lt;code&gt;use&lt;/code&gt; expression. See &lt;a href=&quot;#A-note-of-use-scope&quot;&gt;this note&lt;/a&gt; for more explanation.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;So-What&quot;&gt;
&lt;h2&gt;So What?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve introduced some syntax sugar&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;A &lt;code&gt;use&lt;/code&gt; expression is &lt;a href=&quot;https://en.wikipedia.org/wiki/Syntactic_sugar&quot;&gt;syntactic sugar&lt;/a&gt; for a regular call and an anonymous function. During compilation, a &lt;code&gt;use&lt;/code&gt; expression expands into the &lt;code&gt;fn(arg1, arg2, ...) { body() } &lt;/code&gt; form. It&amp;rsquo;s explicitly to allow a different way of writing expressions.&lt;/span&gt;&lt;/span&gt; that allows me to change how I write functions that take a callback function as their last argument. But in my example, it doesn&amp;rsquo;t help me much. In the example, it&amp;rsquo;s no longer clear that I&amp;rsquo;m writing a callback function, and I can&amp;rsquo;t do anything else after my &lt;code&gt;list.map&lt;/code&gt; call, that doesn&amp;rsquo;t end up in the callback function. &lt;code&gt;list.map&lt;/code&gt; &lt;em&gt;can&lt;/em&gt; be used with a &lt;code&gt;use&lt;/code&gt; expression, but it&amp;rsquo;s a poor choice over the default syntax in most cases.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I chose &lt;code&gt;list.map&lt;/code&gt; &lt;em&gt;because&lt;/em&gt; it&amp;rsquo;s a commonly used Gleam function that is a poor fit for &lt;code&gt;use&lt;/code&gt;. &lt;code&gt;list.map&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; one of my favorite functions though, and I&amp;rsquo;ve used it a lot in one of my other &lt;a href=&quot;/notes/gleam-favorite-feature&quot;&gt;Gleam articles&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So what &lt;em&gt;is&lt;/em&gt; &lt;code&gt;use&lt;/code&gt; useful for?&lt;/p&gt;
&lt;section id=&quot;resultunwrap-and-early-returns&quot;&gt;
&lt;h3&gt;&lt;code&gt;result.unwrap&lt;/code&gt; and early returns&lt;/h3&gt;
&lt;p&gt;Gleam has no exceptions, all errors must be returned as values from a function.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Gleam also has no &lt;code&gt;return&lt;/code&gt; keyword, the last expression in a block is returned as the value of that block. In a function, that&amp;rsquo;s the last thing in the function.&lt;/span&gt;&lt;/span&gt; Specifically, Gleam uses the convention of &lt;a href=&quot;https://tour.gleam.run/data-types/results/&quot;&gt;&lt;code&gt;Result&lt;/code&gt;&lt;/a&gt; to capture this information. Success looks like &lt;code&gt;Ok(value)&lt;/code&gt; and failure looks like &lt;code&gt;Error(reason)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But what if I want to do something that might fail, and then continue to do something else in the same function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result

fn outer() -&amp;gt; Result(success, failure) {
  let id = parse_id() |&amp;gt; result.unwrap(0)
  ... // More code that uses the id
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;parse_id&lt;/code&gt; might fail, and therefore returns a &lt;code&gt;Result&lt;/code&gt;. To use the inner value, we need to unwrap it somehow. On a successful parse, the wrapped value will look like &lt;code&gt;Ok(id)&lt;/code&gt;, and this code uses &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/result.html#unwrap&quot;&gt;&lt;code&gt;result.unwrap&lt;/code&gt;&lt;/a&gt; to pull out the &lt;code&gt;id&lt;/code&gt; on an &lt;code&gt;Ok&lt;/code&gt; case, or set the &lt;code&gt;id&lt;/code&gt; to 0 in the &lt;code&gt;Error&lt;/code&gt; case.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;0&lt;/code&gt; as an id is made up, and likely has no reliable meaning in our system. If we wanted to convey that the id failed to parse, we already had an &lt;code&gt;Error&lt;/code&gt; that we could have returned directly.&lt;/p&gt;
&lt;p&gt;Instead of using &lt;code&gt;result.unwrap&lt;/code&gt;, we can use &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/result.html#map&quot;&gt;&lt;code&gt;result.map&lt;/code&gt;&lt;/a&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Both &lt;code&gt;list.map&lt;/code&gt; and &lt;code&gt;result.map&lt;/code&gt; are named &lt;code&gt;map&lt;/code&gt;, because they are examples of the higher order function &lt;a href=&quot;https://en.wikipedia.org/wiki/Map_(higher-order_function%29&quot;&gt;map&lt;/a&gt; that applies a function to every element of collection.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;In the case of &lt;code&gt;result.map&lt;/code&gt; the &amp;ldquo;collection&amp;rdquo; is only the contents of the &lt;code&gt;Ok&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;s are simply returned without invoking the callback function.&lt;/span&gt;&lt;/span&gt;, which takes a &lt;code&gt;Result&lt;/code&gt; and a callback function, where the callback function is only invoked when the &lt;code&gt;Result&lt;/code&gt; is &lt;code&gt;Ok&lt;/code&gt;. If the Result is an &lt;code&gt;Error&lt;/code&gt; then it returns the &lt;code&gt;Error&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn12&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn12&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is how Gleam can do an &amp;ldquo;early&amp;rdquo; return, &lt;code&gt;result.map&lt;/code&gt; only evaluates the callback function on success, so in the failure case the value of the &lt;code&gt;result.map&lt;/code&gt; expression (and therefore the block) &lt;em&gt;is&lt;/em&gt; the &lt;code&gt;Error&lt;/code&gt;, and it doesn&amp;rsquo;t evaluate any more code.&lt;/span&gt;&lt;/span&gt; The callback function gets the unwrapped, inner value as its one argument.&lt;/p&gt;
&lt;p&gt;So we can do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result

fn outer() -&amp;gt; Result(success, failure) {
  result.map(parse_id(), fn(id) {
    ... // More code that uses the id
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with invoking &lt;code&gt;result.map&lt;/code&gt; this way, is that now all of the internals of &lt;code&gt;outer&lt;/code&gt; are indented inside the callback function. Here, we can use a &lt;code&gt;use&lt;/code&gt; expression to eliminate the extra indentation and focus our function on the success case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result

fn outer() -&amp;gt; Result(success, failure) {
  use id &amp;lt;- result.map(parse_id())
  ... // More code that uses the id
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have still accomplished what we wanted to accomplish, which is that if &lt;code&gt;parse_id&lt;/code&gt; fails, it returns early with the &lt;code&gt;Error&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn13&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn13&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you&amp;rsquo;re familiar with Rust&amp;rsquo;s &lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/std/result/question_mark.html&quot;&gt;&lt;code&gt;?&lt;/code&gt;&lt;/a&gt; operator, the expression &lt;code&gt;use id &amp;lt;- result.map(parse_id())&lt;/code&gt; is equivalent to Rust&amp;rsquo;s &lt;code&gt;let id = parse_id()?;&lt;/code&gt;&lt;/span&gt;&lt;/span&gt; Now, we can focus our code&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn14&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn14&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;and limited attention&lt;/span&gt;&lt;/span&gt; on the unwrapped &lt;code&gt;id&lt;/code&gt; in the success case.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Avoiding-boilerplate-with-resultmap&quot;&gt;
&lt;h3&gt;Avoiding boilerplate with &lt;code&gt;result.map&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;use&lt;/code&gt; expression can also allow you to avoid a lot of boilerplate. For example, reading from a file is an operation that can fail, so it returns a &lt;code&gt;Result&lt;/code&gt;. If I want to read lines from a file and then transform them, I can use &lt;code&gt;result.map&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result
import gleam/list

fn transform_lines() {
  read_file_lines()
  |&amp;gt; result.map(list.filter(...))
  |&amp;gt; result.map(list.map(...))
  |&amp;gt; result.map(list.sort(...))
  |&amp;gt; result.map(something_else())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but because &lt;code&gt;result.map&lt;/code&gt; returns a new &lt;code&gt;Result&lt;/code&gt;, I have to continue chaining &lt;code&gt;result.map&lt;/code&gt; calls until I&amp;rsquo;ve finished all of the transformations that I need.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;use&lt;/code&gt; expression allows us to gracefully handle the failure case, while removing the need for chained calls to &lt;code&gt;result.map&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result
import gleam/list

fn transform_lines() {
  use lines &amp;lt;- result.map(read_file_lines())

  lines
  |&amp;gt; list.filter(...)
  |&amp;gt; list.map(...)
  |&amp;gt; list.sort(...)
  |&amp;gt; something_else()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These two functions are equivalent, but the &lt;code&gt;use&lt;/code&gt; expression allows us to focus on the transformations we care about.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn15&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn15&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Since &lt;code&gt;use&lt;/code&gt; is only syntax sugar, all of the piped transformations &lt;em&gt;could&lt;/em&gt; be written inside &lt;code&gt;result.map&lt;/code&gt;&amp;rsquo;s callback function without a &lt;code&gt;use&lt;/code&gt; expression:&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;fn(lines) { ... }&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Chaining-resulttry&quot;&gt;
&lt;h3&gt;Chaining &lt;code&gt;result.try&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;use&lt;/code&gt; expressions are especially helpful when doing multiple &lt;em&gt;different&lt;/em&gt; things that might fail. &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/result.html#try&quot;&gt;&lt;code&gt;result.try&lt;/code&gt;&lt;/a&gt; takes a &lt;code&gt;Result&lt;/code&gt; and callback function that itself returns a &lt;code&gt;Result&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn16&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn16&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;try&lt;/code&gt; the first thing, then &lt;code&gt;try&lt;/code&gt; a second thing if the first one succeeds.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn17&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn17&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;ve heard this concept of chaining &lt;code&gt;result.try&lt;/code&gt; calls together referred to as railroad-oriented design. If any operation fails, it switches to the &lt;code&gt;Error&lt;/code&gt; &amp;ldquo;track&amp;rdquo; and returns that &lt;code&gt;Error&lt;/code&gt;, otherwise it continues along the &lt;code&gt;Ok&lt;/code&gt; track until the next operation that could fail, which has another &amp;ldquo;railroad switch&amp;rdquo;.&lt;/span&gt;&lt;/span&gt; If the first argument is an &lt;code&gt;Error&lt;/code&gt; it returns that error. Otherwise, it evaluates the callback function and returns whatever &lt;code&gt;Result&lt;/code&gt; that callback function does. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result

fn handle_form(form_data: RegistrationForm) {
  result.try(
    unique_username(form_data.username), 
    fn(username) {
      result.try(
        validate_password(form_data.password), 
        fn(password) {
          result.map(
            register_user(username, password), 
            fn(user) {
              &quot;welcome &quot; &amp;lt;&amp;gt; user.username &amp;lt;&amp;gt; &quot;!&quot;
            }
          )
        }
      )
    }
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because each operation can separately fail, we can&amp;rsquo;t chain these together like I did in the &lt;code&gt;result.map&lt;/code&gt; boilerplate example. This creates a cascade of indented callback functions that makes it hard to keep track of what&amp;rsquo;s going on and what the final return value in the success case is.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn18&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn18&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;ve heard this referred to as callback hell.&lt;/span&gt;&lt;/span&gt; With &lt;code&gt;use&lt;/code&gt; expressions the meaning is much clearer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result

fn handle_form(form_data: RegistrationForm) {
  use username &amp;lt;- result.try(unique_username(form_data.username))
  use password &amp;lt;- result.try(validate_password(form_data.password))
  use user &amp;lt;- result.map(register_user(username, password))
  
  &quot;welcome &quot; &amp;lt;&amp;gt; user.username &amp;lt;&amp;gt; &quot;!&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here it&amp;rsquo;s much easier to tell which operations we&amp;rsquo;re doing, and what the final return value is.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn19&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn19&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The last operation uses &lt;code&gt;result.map&lt;/code&gt; because we&amp;rsquo;re finally returning something that can&amp;rsquo;t fail. It was the same in the first example, did you notice?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Context-Management&quot;&gt;
&lt;h3&gt;Context Management&lt;/h3&gt;
&lt;p&gt;Another place where &lt;code&gt;use&lt;/code&gt; expressions shine is with context management: functions that do setup, cleanup, or both. In Gleam, there&amp;rsquo;s no special way of handling context management, and so these functions use a callback function as an argument to wrap the user behavior they&amp;rsquo;re managing. For example, opening a database connection with &lt;a href=&quot;https://hexdocs.pm/sqlight/&quot;&gt;&lt;code&gt;sqlight&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import sqlight

fn get_data() {
  use conn &amp;lt;- sqlight.with_connection(&quot;my_database.db&quot;)
  
  ... // query the database
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/sqlight/sqlight.html#with_connection&quot;&gt;&lt;code&gt;sqlight.with_connection&lt;/code&gt;&lt;/a&gt; will open a connection to the database, execute code, and then close the connection afterwards. The database connection is available as &lt;code&gt;conn&lt;/code&gt; for the rest of the function. Technically, all of the user code is wrapped in a function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import sqlight

fn get_data() {
  sqlight.with_connection(&quot;my_database.db&quot;, fn(conn) {
       ... // query the database
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but the &lt;code&gt;use&lt;/code&gt; expression allows us to focus on the query we want to write, not on database management.&lt;/p&gt;
&lt;p&gt;Another example of this kind of callback function wrapper comes from &lt;a href=&quot;https://hexdocs.pm/wisp/&quot;&gt;&lt;code&gt;wisp&lt;/code&gt;&lt;/a&gt;, Gleam&amp;rsquo;s web framework:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn20&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn20&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This example comes from wisp&amp;rsquo;s &lt;a href=&quot;https://github.com/gleam-wisp/wisp/blob/main/examples/07-logging/src/app/web.gleam&quot;&gt;logging example&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import wisp

pub fn middleware(
  req: wisp.Request,
  handle_request: fn(wisp.Request) -&amp;gt; wisp.Response,
) -&amp;gt; wisp.Response {
  let req = wisp.method_override(req)
  use &amp;lt;- wisp.log_request(req)
  use &amp;lt;- wisp.rescue_crashes
  use req &amp;lt;- wisp.handle_head(req)

  handle_request(req)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;a href=&quot;https://hexdocs.pm/wisp/wisp.html#log_request&quot;&gt;&lt;code&gt;wisp.log_request&lt;/code&gt;&lt;/a&gt; uses a callback function to allow logging to take place after a request has been handled, regardless of how the user of &lt;code&gt;wisp&lt;/code&gt; chooses to do that handling.&lt;/p&gt;
&lt;p&gt;The other &lt;code&gt;wisp&lt;/code&gt; functions use a similar pattern allowing for customization to the application while still handling core web application concerns.&lt;/p&gt;
&lt;p&gt;This is also an example of &lt;code&gt;use&lt;/code&gt; expressions preventing cascading nested callbacks, without &lt;code&gt;use&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import wisp

pub fn middleware(
  req: wisp.Request,
  handle_request: fn(wisp.Request) -&amp;gt; wisp.Response,
) -&amp;gt; wisp.Response {
  let req = wisp.method_override(req)
  wisp.log_request(req, fn() {
    wisp.rescue_crashes(fn() {
      wisp.handle_head(req, fn(req) { 
        handle_request(req)
      })
    })
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without &lt;code&gt;use&lt;/code&gt;, how the request is being handled is obscured by the nested callback functions used to manage &lt;code&gt;wisp&lt;/code&gt; request context.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn21&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn21&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This example has three of these context manager functions, but I&amp;rsquo;ve seen &lt;code&gt;wisp&lt;/code&gt; applications with 8 or more. You &lt;em&gt;could&lt;/em&gt; write that without &lt;code&gt;use&lt;/code&gt;, but the &lt;code&gt;use&lt;/code&gt; expressions allow the custom logic to remain readable.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve shared a number of examples where &lt;code&gt;use&lt;/code&gt; expressions can add clarity to code, both with error handling and context management. As I showed in the &lt;code&gt;list.map&lt;/code&gt; example, &lt;code&gt;use&lt;/code&gt; expressions aren&amp;rsquo;t &lt;em&gt;always&lt;/em&gt; helpful. The key is to use &lt;code&gt;use&lt;/code&gt; when it allows you to highlight the happy path of your code, while handling concerns like failure and logging.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn22&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn22&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thank you to &lt;a href=&quot;https://ntietz.com&quot;&gt;Nicole&lt;/a&gt;, &lt;a href=&quot;http://www.aristobit.com/blog/&quot;&gt;Jeff Miller&lt;/a&gt;, and &lt;a href=&quot;https://github.com/markholmes&quot;&gt;Mark&lt;/a&gt;, as well as the Gleam discord for helping me write and edit this article.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;use&lt;/code&gt; expression is syntax sugar, and it&amp;rsquo;s always possible to write Gleam code without it, though maybe not as clearly.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn23&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn23&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Why &lt;code&gt;use&lt;/code&gt;, specifically, as a keyword? &lt;a href=&quot;https://github.com/gleam-lang/gleam/issues/1709&quot;&gt;This issue&lt;/a&gt; highlighted the need for a general syntax sugar. &lt;a href=&quot;https://koka-lang.github.io/koka/doc/book.html#sec-with&quot;&gt;&lt;code&gt;with&lt;/code&gt; statements&lt;/a&gt; in &lt;a href=&quot;https://koka-lang.github.io/koka/doc/index.html&quot;&gt;koka&lt;/a&gt; were identified as a similar solution, but &lt;code&gt;with&lt;/code&gt; was already a well-used special form &lt;a href=&quot;https://hexdocs.pm/elixir/1.17.1/Kernel.SpecialForms.html#with/1&quot;&gt;in Elixir&lt;/a&gt;, and Gleam didn&amp;rsquo;t want to confuse BEAM programmers coming from Elixir.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;After a lot of discussion &lt;code&gt;use&lt;/code&gt; was chosen, in part because it&amp;rsquo;s the same length as &lt;code&gt;let&lt;/code&gt; and it wasn&amp;rsquo;t already in use anywhere.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Additional-Notes&quot;&gt;
&lt;h2&gt;Additional Notes&lt;/h2&gt;
&lt;section id=&quot;A-note-of-use-scope&quot;&gt;
&lt;h3&gt;A note of &lt;code&gt;use&lt;/code&gt; scope&lt;/h3&gt;
&lt;p&gt;Everything below the &lt;code&gt;use&lt;/code&gt; expression comprises the body of the callback function &lt;em&gt;until the end of the current block&lt;/em&gt;. By default, this will be the end of the function, but we can use &lt;code&gt;{}&lt;/code&gt; to create a smaller block:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn24&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn24&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;From the &lt;a href=&quot;https://tour.gleam.run/advanced-features/use-sugar/&quot;&gt;language tour&lt;/a&gt;: &amp;ldquo;&lt;code&gt;use&lt;/code&gt; is an expression like everything else in Gleam, so it can be placed within blocks.&amp;rdquo;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/result

fn example() {
  let smaller_block = {
    use value &amp;lt;- result.try(thing_that_might_fail())
    ... // do something with the value
  }

  no_longer_in_use_callback(smaller_block)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A example of this comes from the new &lt;a href=&quot;https://hexdocs.pm/decode/&quot;&gt;&lt;code&gt;decode&lt;/code&gt;&lt;/a&gt; library:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn25&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn25&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This example comes from the &lt;a href=&quot;https://hexdocs.pm/decode/0.2.0/index.html&quot;&gt;README&lt;/a&gt; for &lt;code&gt;decode&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let decoder =
  decode.into({
    use name &amp;lt;- decode.parameter
    use email &amp;lt;- decode.parameter
    use is_admin &amp;lt;- decode.parameter
    User(name, email, is_admin)
  })
  |&amp;gt; decode.field(&quot;name&quot;, decode.string)
  |&amp;gt; decode.field(&quot;email&quot;, decode.string)
  |&amp;gt; decode.field(&quot;is-admin&quot;, decode.bool)

decoder
|&amp;gt; decode.from(data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;a href=&quot;https://hexdocs.pm/decode/decode.html#into&quot;&gt;&lt;code&gt;decode.into&lt;/code&gt;&lt;/a&gt; is using a &lt;code&gt;{}&lt;/code&gt; block to succinctly create a decoder function using a combination of &lt;code&gt;use&lt;/code&gt; and &lt;a href=&quot;https://hexdocs.pm/decode/decode.html#parameter&quot;&gt;&lt;code&gt;decode.parameter&lt;/code&gt;&lt;/a&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn26&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn26&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is a clever use of &lt;code&gt;use&lt;/code&gt; as syntax sugar, since &lt;code&gt;decode.parameter&lt;/code&gt; simply returns its argument. So the above block translates to:&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;fn(name) { fn(email) { fn(is_admin) { User(name, email, is_admin) }}}&lt;/code&gt;&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Which is much harder to read, especially since the ordering of fields matters.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;A-note-on-use-arguments&quot;&gt;
&lt;h3&gt;A note on &lt;code&gt;use&lt;/code&gt; arguments&lt;/h3&gt;
&lt;p&gt;The number of arguments in the &lt;code&gt;use&lt;/code&gt; expression are exactly the same as the arguments required for the callback function being replaced.&lt;/p&gt;
&lt;section id=&quot;boolguard&quot;&gt;
&lt;h4&gt;&lt;code&gt;bool.guard&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html#fold&quot;&gt;&lt;code&gt;bool.guard&lt;/code&gt;&lt;/a&gt; takes a function that requires no arguments:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn27&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn27&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;fn() -&amp;gt; a&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// without `use`
bool.guard(condition, &quot;early return&quot;, fn() {
  ...
  &quot;late return&quot;
})

// with `use`
use &amp;lt;- bool.guard(condition, &quot;early return&quot;)
...
&quot;late return&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;listfold&quot;&gt;
&lt;h4&gt;&lt;code&gt;list.fold&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html#fold&quot;&gt;&lt;code&gt;list.fold&lt;/code&gt;&lt;/a&gt; takes a functions that requires &lt;em&gt;two&lt;/em&gt; arguments.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn28&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn28&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;fn(a, a) -&amp;gt; a&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;// without `use`
list.fold(numbers, 1, fn(accumulator, element) {
  accumulator * element
})

// with `use`
use accumulator, element &amp;lt;- list.fold(numbers, 1)
accumulator * element
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/using-use-gleam</id>
<link href="https://erikarow.land/notes/using-use-gleam" />
<title>Using use in Gleam</title>
<updated>2024-07-27T00:00:00+00:00</updated>
<dc:date>2024-07-08T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Tools-I-Use-firefox&quot;&gt;
&lt;h1&gt;Tools I Use: firefox&lt;/h1&gt;
&lt;p&gt;Firefox is my daily use browser. I&amp;rsquo;ve tried a number of browsers over the years, but I keep coming back to Firefox. Here&amp;rsquo;s a bunch of tools and features I use in Firefox:&lt;/p&gt;
&lt;section id=&quot;Bookmark-Keywords&quot;&gt;
&lt;h2&gt;Bookmark Keywords&lt;/h2&gt;
&lt;p&gt;Firefox allows me to add keywords to bookmarks. I can type these abbreviated shortcuts into the address bar instead of the full link. I can add keywords to bookmarks from the bookmark manager.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I learned about bookmark keywords from &lt;a href=&quot;https://blog.meain.io/2024/firefox-bookmark-keywords&quot;&gt;this excellent blog post&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://support.mozilla.org/en-US/kb/bookmarks-firefox#w_how-to-use-keywords-with-bookmarks&quot;&gt;Here&lt;/a&gt; is a brief note in the documentation on bookmark keywords.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For example, I&amp;rsquo;ve set the shortcut &lt;code&gt;e&lt;/code&gt; for my website (&lt;code&gt;erikarow.land&lt;/code&gt;), since I use my own website as reference notes.&lt;/p&gt;
&lt;p&gt;Now I can type &lt;code&gt;e&lt;/code&gt; in the address bar and go directly to my website.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I often use the &lt;code&gt;ctrl+l&lt;/code&gt; shortcut to quickly access the address bar. On MacOS the shortcut is &lt;code&gt;cmd+l&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;Text-substitution&quot;&gt;
&lt;h3&gt;Text substitution&lt;/h3&gt;
&lt;p&gt;In addition to setting a keyword for a static bookmark, I can also use &lt;code&gt;%s&lt;/code&gt; in the bookmark url for text substitution.&lt;/p&gt;
&lt;p&gt;For example, I can set a bookmark for&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://bookshop.org/search?keywords=%s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with a keyword of &lt;code&gt;bk&lt;/code&gt;. Then I can type &lt;code&gt;bk data feminism&lt;/code&gt; in the address bar to search for that book.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I own Data Feminism in physical copy already. You can read it online for free &lt;a href=&quot;https://data-feminism.mitpress.mit.edu/&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;And download an open access pdf &lt;a href=&quot;https://direct.mit.edu/books/book/4660/Data-Feminism&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Check out the research the Data Feminism lab is doing now at &lt;a href=&quot;https://dataplusfeminism.mit.edu/&quot;&gt;their website&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;While working on a project, I could use bookmark keywords and text substitution to search through tickets or code forge issues.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Address-bar-search-tab-search&quot;&gt;
&lt;h2&gt;Address bar search (tab search)&lt;/h2&gt;
&lt;p&gt;The Firefox address bar can be used to quickly access a search engine. But Firefox also has alternate search shortcuts that can be used to narrow the  suggestions that the address bar gives as autocompletions.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I first heard of these from &lt;a href=&quot;https://wiki.tilde.institute/w/firefox-address-bar-tips&quot;&gt;this article&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The autocomplete search I use most often is tab search. If I open the address bar and type &lt;code&gt;%&lt;/code&gt; followed by a space, it autocompletes on only my open tabs. It&amp;rsquo;s often easier for me to search for an open tab than to manually scan for it, especially if I have a large number of open tabs.&lt;/p&gt;
&lt;p&gt;There are a number of these built in:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;List retrieved from the &lt;a href=&quot;https://support.mozilla.org/en-US/kb/address-bar-autocomplete-firefox#w_changing-results-on-the-fly&quot;&gt;firefox documentation&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Add &lt;code&gt;^&lt;/code&gt; to show only matches in your browsing history.
&lt;/li&gt;
&lt;li&gt;
Add &lt;code&gt;*&lt;/code&gt; to show only matches in your bookmarks.
&lt;/li&gt;
&lt;li&gt;
Add &lt;code&gt;+&lt;/code&gt; to show only matches in bookmarks you&amp;rsquo;ve tagged.
&lt;/li&gt;
&lt;li&gt;
Add &lt;code&gt;%&lt;/code&gt; to show only matches in your currently open tabs.
&lt;/li&gt;
&lt;li&gt;
Add &lt;code&gt;#&lt;/code&gt; to show only matches where every search term is part of the title or part of a tag.
&lt;/li&gt;
&lt;li&gt;
Add &lt;code&gt;$&lt;/code&gt; to show only matches where every search term is part of the web address (URL). The text “https://” or “http://” in the URL is ignored, but not “file:///”.
&lt;/li&gt;
&lt;li&gt;
Add &lt;code&gt;?&lt;/code&gt; to show only search suggestions.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Screenshot-Tool&quot;&gt;
&lt;h2&gt;Screenshot Tool&lt;/h2&gt;
&lt;p&gt;Firefox has a built in screenshot tool which I wrote about &lt;a href=&quot;/notes/firefox-screenshot-tool&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Process-Manager&quot;&gt;
&lt;h2&gt;Process Manager&lt;/h2&gt;
&lt;p&gt;Firefox has a built in process manager that allows me to see the CPU and Memory usage of every tab that I have open. With the browser acting as application platform, this is quite useful.&lt;/p&gt;
&lt;p&gt;The process manager gives me the ability to unload tabs and kill the process for a specific website. When I want to do something memory intensive on my computer, I can unload a bunch of expensive browser applications.&lt;/p&gt;
&lt;p&gt;The process manager can be opened with &lt;code&gt;shift+escape&lt;/code&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Developer-Tools&quot;&gt;
&lt;h2&gt;Developer Tools&lt;/h2&gt;
&lt;p&gt;Firefox has a suite of web developer tools. There&amp;rsquo;s way more than I know how to use, but I use some of the tools often:&lt;/p&gt;
&lt;section id=&quot;Mobile-View&quot;&gt;
&lt;h3&gt;Mobile View&lt;/h3&gt;
&lt;p&gt;Firefox has a responsive design mode, which allows me to see what my website would look like at different resolutions. I use the response design mode to see what my website would look and act like on a mobile screen. My sidenotes wouldn&amp;rsquo;t work unchanged on a mobile screen, so they turn into expandable notes.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Inspector&quot;&gt;
&lt;h3&gt;Inspector&lt;/h3&gt;
&lt;p&gt;I often use the inspector tool to see how a specific element of a screen was formatted or styled. What HTML did they use? What CSS styles are active on that component?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Developer-Tool-Keyboard-shortcuts&quot;&gt;
&lt;h3&gt;Developer Tool Keyboard shortcuts&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
Developer Tools | &lt;code&gt;F12&lt;/code&gt; or &lt;code&gt;ctrl+shift+i&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;A list of all the developer tool shortcuts can be found &lt;a href=&quot;https://firefox-source-docs.mozilla.org/devtools-user/keyboard_shortcuts/index.html&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Non developer shortcuts can be found &lt;a href=&quot;https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
Mobile View | &lt;code&gt;ctrl+shift+m&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
Inspector | &lt;code&gt;ctrl+shift+c&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
Console | &lt;code&gt;ctrl+shift+k&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Pinned-Tabs&quot;&gt;
&lt;h2&gt;Pinned Tabs&lt;/h2&gt;
&lt;p&gt;I like to pin tabs that I refer to frequently, typically social media&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Mastodon, etc.&lt;/span&gt;&lt;/span&gt; and chat applications&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Community Slacks, etc.&lt;/span&gt;&lt;/span&gt; that I use from the browser.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I tend to use the browser clients for these chat applications because of how easy it is to find them with the pinned tab feature.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A pinned tab shows only an icon instead of a title, stays to the left of the browser window it&amp;rsquo;s pinned to, and does not get closed when using &lt;code&gt;ctrl+f4&lt;/code&gt; or &lt;code&gt;ctrl+w&lt;/code&gt; to close a tab.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;A pinned tab must be unpinned before it can be closed by keyboard shortcuts. Right clicking the tab and selecting &amp;ldquo;Close Tab&amp;rdquo; will still work.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I can pin a tab by right clicking that tab, and selecting &amp;ldquo;Pin Tab&amp;rdquo; from the menu.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Always-Show-Scroll-Bars&quot;&gt;
&lt;h2&gt;Always Show Scroll Bars&lt;/h2&gt;
&lt;p&gt;By default, Firefox will autohide scroll bars after a short while. There is a setting to have scrollbars always show. I wrote an article about that &lt;a href=&quot;https://erikarow.land/notes/firefox-always-show-scrollbar&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Tab-Settings&quot;&gt;
&lt;h2&gt;Tab Settings&lt;/h2&gt;
&lt;p&gt;I have Firefox set to &amp;ldquo;Open previous windows and tabs&amp;rdquo; on startup. This restore makes it easier to close Firefox when I need to reboot or free up the memory firefox uses for something else.&lt;/p&gt;
&lt;p&gt;I also turn &lt;em&gt;off&lt;/em&gt; the setting for &amp;ldquo;Ctrl+Tab cycles through tabs in recently used order&amp;rdquo;. I want my tab cycling to be predictable.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn12&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn12&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Both of these tab settings are found under Settings -&amp;gt; General.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Learn more about restoring sessions &lt;a href=&quot;https://support.mozilla.org/en-US/kb/restore-previous-session#w_configuring-session-restore&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Extensions&quot;&gt;
&lt;h2&gt;Extensions&lt;/h2&gt;
&lt;p&gt;The extensions I use are:&lt;/p&gt;
&lt;section id=&quot;uBlock-Origin&quot;&gt;
&lt;h3&gt;uBlock Origin&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/&quot;&gt;uBlock Origin&lt;/a&gt; is a memory efficient ad blocker. It works, no complaints.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn13&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn13&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It works so well that I forget how many ads there are the internet, only to be rudely reminded when I use other computers or browsers without uBlock Origin.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;ClearURLs-and-Privacy-Badger&quot;&gt;
&lt;h3&gt;ClearURLs and Privacy Badger&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.clearurls.xyz/1.26.1/&quot;&gt;ClearURLs&lt;/a&gt; automatically removes tracking elements from URLs. When I click links that have tracking components, this extension will automatically strip them out.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://privacybadger.org/&quot;&gt;Privacy Badger&lt;/a&gt; detects any remaining third-party trackers that follow me from site to site, and stops them.&lt;/p&gt;
&lt;p&gt;Both of these extensions work to improve my privacy, but when they&amp;rsquo;re working correctly I don&amp;rsquo;t notice them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;DF-YouTube-Distraction-Free&quot;&gt;
&lt;h3&gt;DF YouTube (Distraction Free)&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/df-youtube/&quot;&gt;DF Youtube&lt;/a&gt; strips nearly everything from the YouTube UI. No comments. No sidebar. No recommended videos.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m left with a search bar and the playing video and description, and my focus.&lt;/p&gt;
&lt;p&gt;I use DF YouTube to view videos on YouTube without getting distracted or stuck in a YouTube rabbit hole.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;OneTab&quot;&gt;
&lt;h3&gt;OneTab&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.one-tab.com/&quot;&gt;OneTab&lt;/a&gt; will compress open tabs into a simple list with much smaller memory usage. It allows me to archive what I was working on without using all of my computer&amp;rsquo;s memory.&lt;/p&gt;
&lt;p&gt;All tabs get saved to the same list, separated into groups based on when they were added to the &amp;ldquo;One Tab&amp;rdquo;. This list format is convenient for text search.&lt;/p&gt;
&lt;p&gt;Previously, I would &amp;ldquo;archive&amp;rdquo; things I wanted to read by bookmarking them to come back to later, now I use OneTab for this purpose.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn14&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn14&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Like my bookmarks, I tend to add things to the list much quicker than I remove things. At time of writing, I have 11,000+ &amp;ldquo;tabs&amp;rdquo; listed in OneTab.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Block-Site&quot;&gt;
&lt;h3&gt;Block Site&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://webextension.org/listing/block-site.html&quot;&gt;Block Site&lt;/a&gt; allows me to restrict access to specific domains. When navigating to a blocked domain, instead of seeing that site, I see a specific &amp;ldquo;Restricted Access&amp;rdquo; screen created by the extension.&lt;/p&gt;
&lt;p&gt;I use this to circuit break websites that I check compulsively. I can temporarily disable the extension at any time to navigate to those websites, but having the restricted screen is enough of a mental block that I usually stop checking those websites as often.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;aboutrobots&quot;&gt;
&lt;h2&gt;&lt;code&gt;about:robots&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Firefox has a hidden &lt;code&gt;about:robots&lt;/code&gt; page with references to pop culture.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn15&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn15&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to someone in the Gleam discord for sharing this with me.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/tools-use-firefox</id>
<link href="https://erikarow.land/notes/tools-use-firefox" />
<title>Tools I Use: firefox</title>
<updated>2024-07-15T00:00:00+00:00</updated>
<dc:date>2024-07-15T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Things-I-like-about-Gleams-Syntax&quot;&gt;
&lt;h1&gt;Things I like about Gleam&amp;rsquo;s Syntax&lt;/h1&gt;
&lt;p&gt;Gleam is a Type-Safe programming language that transpiles to Erlang&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;And &lt;a href=&quot;https://gleam.run/news/v0.16-gleam-compiles-to-javascript/&quot;&gt;javascript&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;, so you can run its code on the BEAM. I&amp;rsquo;ve slept on Gleam for a while because its syntax. It was too much Rust and not enough Elixir for me.&lt;/p&gt;
&lt;p&gt;Recently, I was reminded of Gleam when someone mentioned that Gleam doesn&amp;rsquo;t have an if statement, but instead uses &lt;code&gt;case&lt;/code&gt; for everything. As a consequence, I ended up re-reading the &lt;a href=&quot;https://gleam.run/book/tour/index.html&quot;&gt;Gleam language tour&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As another reminder to check my assumptions from time to time,
Gleam&amp;rsquo;s syntax has some goodies that I hadn&amp;rsquo;t noticed before,
It&amp;rsquo;s definitely grown on me now that I&amp;rsquo;ve used Rust for a while.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Gleam&amp;rsquo;s syntax draws a lot from Rust&amp;rsquo;s syntax. Gleam&amp;rsquo;s transpiler is &lt;a href=&quot;https://github.com/gleam-lang/gleam&quot;&gt;written in Rust&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;section id=&quot;Handy-pipe-operator&quot;&gt;
&lt;h2&gt;Handy pipe operator&lt;/h2&gt;
&lt;p&gt;Gleam adopts a &lt;a href=&quot;https://tour.gleam.run/functions/pipelines/&quot;&gt;pipe operator&lt;/a&gt; similar to Elixir&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Gleam&amp;rsquo;s &lt;code&gt;list.at&lt;/code&gt; function returns a &lt;code&gt;Result&lt;/code&gt; type, which allows me to know whether I&amp;rsquo;ve received a value from the list or used an index outside the bounds of the list. The former will be &lt;code&gt;Ok(value)&lt;/code&gt; and the latter will return &lt;code&gt;Err(Nil)&lt;/code&gt; per the type signature of &lt;code&gt;list.at&lt;/code&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is in contrast to Elixir&amp;rsquo;s &lt;code&gt;Enum.at/2&lt;/code&gt; function, which returns &lt;code&gt;value&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt; with no indication of whether that &lt;code&gt;nil&lt;/code&gt; came from the list or from an out-of-bounds index.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/io
import gleam/list

pub fn main() {
  [1, 2, 3]
  |&amp;gt; list.append([4,5,6])
  |&amp;gt; list.reverse
  |&amp;gt; list.at(2) 
  |&amp;gt; io.debug() // prints Ok(4)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Labeled-arguments&quot;&gt;
&lt;h2&gt;Labeled arguments&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/10091185/piping-composition-and-currying&quot;&gt;Labeled arguments&lt;/a&gt; is how Gleam does keyword arguments which are notably missing from both Elixir and Rust. So this is a great addition. The main benefit of labeled arguments is that you can pass them into the function in any order, since they&amp;rsquo;re identified by name.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note that I had to use &lt;code&gt;name&lt;/code&gt; twice in &lt;code&gt;greet&lt;/code&gt;. The first time is the label, the second time is the variable I use in the body of the function. Using one &lt;code&gt;name&lt;/code&gt; by itself raises a compiler error.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Elixir can simulate keyword arguments with keyword lists, but those require a &lt;code&gt;Keyword.get&lt;/code&gt; call to retrieve keys inside the function body, and can&amp;rsquo;t be passed in positionally.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/io

fn greet(name name: String, in place: String) {
  &quot;Hello &quot; &amp;lt;&amp;gt; name &amp;lt;&amp;gt; &quot; from &quot; &amp;lt;&amp;gt; place
}

pub fn main() {
  greet(name: &quot;Christine&quot;, in: &quot;NASA&quot;)
  |&amp;gt; io.debug() // &quot;Hello Christine from NASA&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Elegant-function-capturing&quot;&gt;
&lt;h2&gt;Elegant function capturing&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://tour.gleam.run/functions/function-captures/&quot;&gt;Function capturing&lt;/a&gt; allows me to quickly create a one-argument anonymous function from a named function. The one argument will go wherever I place the &lt;code&gt;_&lt;/code&gt; in the function capture. It only seems to work for creating one-argument anonymous functions,
putting multiple &lt;code&gt;_&lt;/code&gt; in a capture will compile error&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;By contrast, in Elixir you can have arbitrarily many arguments in a captured function with the numbered &lt;code&gt;&amp;amp;&lt;/code&gt; syntax: &lt;code&gt;&amp;amp;Enum.reduce([1, 2, 3], &amp;amp;1, &amp;amp;2)&lt;/code&gt;&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;(At least, I think it&amp;rsquo;s arbitrarily many, I stopped checking after &lt;code&gt;&amp;amp;11&lt;/code&gt; worked)&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/io
import gleam/list
import gleam/string

pub fn main() {
  let prepend = string.append(&quot;other &quot;, _)

  list.map([&quot;hello&quot;, &quot;world&quot;], prepend) 
  |&amp;gt; io.debug() // [&quot;other hello&quot;, &quot;other world&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Function capturing is also nice for arranging functions for the pipe operator, since Gleam lets me pipe directly into an anonymous function&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Elixir does not let you pipe directly into an anonymous function. In Elixir 1.12.0, &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.html#then/2&quot;&gt;&lt;code&gt;then/2&lt;/code&gt;&lt;/a&gt; was added to remedy this problem.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/io
import gleam/string

pub fn main() {
  &quot;hello&quot;
  |&amp;gt; string.append(&quot;some text &quot;, _)
  |&amp;gt; io.debug()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Only-case-statement-no-if&quot;&gt;
&lt;h2&gt;Only case statement, no if&lt;/h2&gt;
&lt;p&gt;Gleam &lt;a href=&quot;https://gleam.run/book/tour/case-expressions.html#checking-equality-and-ordering-in-patterns&quot;&gt;doesn&amp;rsquo;t have an if statement&lt;/a&gt;, it uses case for that instead&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Gleam does use &lt;code&gt;if&lt;/code&gt; as a keyword, but only in &lt;a href=&quot;https://gleam.run/book/tour/case-expressions.html#checking-equality-and-ordering-in-patterns&quot;&gt;guard expressions&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;case if_boolean {
  True -&amp;gt; &quot;case statements only&quot;
  False -&amp;gt; &quot;you didn&#x27;t get a choice&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like this syntax better than an if statement. It shines a spotlight on the branch, makes it clear which path belongs to which condition, and Gleam will do exhaustiveness checking to force me to handle both cases.&lt;/p&gt;
&lt;p&gt;It also makes it easier to refactor into a sum type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;type CaseExample {
  CaseGood
  CaseAnyway
  ThirdOption
}

case case_example {
  CaseGood -&amp;gt; &quot;case statements only&quot;
  CaseAnyway -&amp;gt; &quot;you didn&#x27;t get a choice&quot;
  ThirdOption -&amp;gt; &quot;more choices!&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Sub-pattern-names-using-as&quot;&gt;
&lt;h2&gt;Sub pattern names using &lt;code&gt;as&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Gleam lets me &lt;a href=&quot;https://gleam.run/book/tour/case-expressions.html#assigning-names-to-sub-patterns&quot;&gt;assign names to sub-patterns&lt;/a&gt; using &lt;code&gt;as&lt;/code&gt; in pattern matching expressions. Elixir solved this problem by making &lt;code&gt;=&lt;/code&gt; expressions return their value, so you could use them in pattern matching, but I always found that somewhat awkward. &lt;code&gt;as&lt;/code&gt; makes it clear that I&amp;rsquo;m naming a sub-pattern for reuse.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;case list {
  [[_, ..] as inner_list] -&amp;gt; inner_list
  other -&amp;gt; []  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that Gleam makes it easy to destructure types with custom variables, avoiding the need for &lt;code&gt;as&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;// example, use gleam/option.Option instead
type OptionalString {
  Some(string: String)
  None
} 

fn unpack_string(optional_string) {
  case optional_string {
    Some(chosen_variable) -&amp;gt; chosen_variable
    None -&amp;gt; &quot;&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Succinct-alternative-clause-patterns-using&quot;&gt;
&lt;h2&gt;Succinct alternative clause patterns using &lt;code&gt;|&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Gleam lets you succinctly specify &lt;a href=&quot;https://gleam.run/book/tour/case-expressions.html#alternative-clause-patterns&quot;&gt;alternate patterns&lt;/a&gt; in a case statement using &lt;code&gt;|&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;type NumberKind {
  Prime
  Composite
}

case number {
  2 | 3 | 5 | 7 -&amp;gt; Prime
  _ -&amp;gt; Composite
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Support-for-todo-to-mark-uncompleted-work&quot;&gt;
&lt;h2&gt;Support for &lt;code&gt;todo&lt;/code&gt; to mark uncompleted work&lt;/h2&gt;
&lt;p&gt;Gleam includes a &lt;a href=&quot;https://gleam.run/book/tour/todo-and-panic.html#todo--panic&quot;&gt;todo&lt;/a&gt; keyword to indicate that some code isn&amp;rsquo;t finished. That code will type check, but will raise a warning on compilation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn fancy(something: SomeComplexType) {
  todo
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The warning:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This code will crash if it is run. Be sure to finish it before
running your program.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Gleam lets me add a description to the &lt;code&gt;todo&lt;/code&gt; using &lt;code&gt;as&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/io

pub fn main() {
  let incomplete = fn(x) {
    case x {
      2 | 3 | 5 | 7 -&amp;gt; &quot;Prime&quot;
      _ -&amp;gt; todo as &quot;Something about composite numbers&quot;
    }
  }
  incomplete(7)
  |&amp;gt; io.debug()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;I really like what Gleam has done with its syntax. Despite my initial misgivings, I&amp;rsquo;m finding it hard not to play with Gleam as I write this article.&lt;/p&gt;
&lt;p&gt;If Gleam&amp;rsquo;s syntax initially put you off, consider giving it another look. I know I like what I found.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/gleam-syntax</id>
<link href="https://erikarow.land/notes/gleam-syntax" />
<title>Things I like about Gleam&#x27;s Syntax</title>
<updated>2024-07-06T00:00:00+00:00</updated>
<dc:date>2023-10-25T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;How-to-Embed-an-SVG-in-CSS&quot;&gt;
&lt;h1&gt;How to Embed an SVG in CSS&lt;/h1&gt;
&lt;p&gt;Recently, I needed to use an SVG as a background image in CSS. I didn&amp;rsquo;t want to host the SVG somewhere, so I couldn&amp;rsquo;t just link to it. I did have access to the SVG source, so I wondered if I could embed it. As I quickly found out, you can use a data URL.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I use CSS data URLs to embed the fonts I use for this website. I didn&amp;rsquo;t know they could be used for SVGs too. Here&amp;rsquo;s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/url#using_a_data_url&quot;&gt;an example on MDN&lt;/a&gt; doing just that.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I initially learned how to do this from &lt;a href=&quot;https://stackoverflow.com/questions/10768451/inline-svg-in-css#10768631&quot;&gt;this stack overflow post&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;Embedding-a-specific-SVG&quot;&gt;
&lt;h2&gt;Embedding a specific SVG&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s work through an example with this SVG triangle:&lt;/p&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;150&quot; height=&quot;150&quot; viewBox=&quot;0 0 203 203&quot; fill=&quot;none&quot;&gt;&lt;polyline points=&quot;100,3 200,200 3,200 100,3&quot; fill=&quot;none&quot; stroke=&quot;pink&quot; stroke-width=&quot;3&quot;/&gt;&lt;/svg&gt;
&lt;p&gt;The SVG source looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; 
  width=&quot;150&quot; height=&quot;150&quot; 
  viewBox=&quot;0 0 203 203&quot; 
  fill=&quot;none&quot;&amp;gt;
    &amp;lt;polyline points=&quot;100,3 200,200 3,200 100,3&quot; 
      fill=&quot;none&quot; stroke=&quot;pink&quot; stroke-width=&quot;3&quot;/&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;section id=&quot;SVG-Data-URL&quot;&gt;
&lt;h3&gt;SVG Data URL&lt;/h3&gt;
&lt;p&gt;The general format for an SVG data url is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data:image/svg+xml;utf8,[some actual SVG here]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So in theory we could paste our SVG from above like this:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you paste this into the browser bar in Firefox, it renders the pink triangle.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data:image/svg+xml;utf8,&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;150&quot; height=&quot;150&quot; viewBox=&quot;0 0 203 203&quot; fill=&quot;none&quot;&amp;gt;&amp;lt;polyline points=&quot;100,3 200,200 3,200 100,3&quot; fill=&quot;none&quot; stroke=&quot;pink&quot; stroke-width=&quot;3&quot;/&amp;gt;&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, to use the CSS &lt;code&gt;url()&lt;/code&gt; function, we need to enclose the data URL in double quotes &lt;code&gt;&quot;&quot;&lt;/code&gt;, which means that our SVG needs to use single quotes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;background-image: url(
  &quot;data:image/svg+xml;utf8,&amp;lt;svg xmlns=&#x27;http://www.w3.org/2000/svg&#x27; width=&#x27;150&#x27; height=&#x27;150&#x27; viewBox=&#x27;0 0 203 203&#x27; fill=&#x27;none&#x27;&amp;gt;&amp;lt;polyline points=&#x27;100,3 200,200 3,200 100,3&#x27; fill=&#x27;none&#x27; stroke=&#x27;pink&#x27; stroke-width=&#x27;3&#x27;/&amp;gt;&amp;lt;/svg&amp;gt;&quot;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, any SVG content needs to be URL escaped, for example &lt;code&gt;#&lt;/code&gt; used for SVG colors need to be replaced with &lt;code&gt;%23&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;My example triangle doesn&amp;rsquo;t have any, but this replacement proved vital for my actual use case.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To be safe, you could URL escape the entire SVG, which is what MDN does in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/url#using_a_data_url&quot;&gt;this example&lt;/a&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In practice, I didn&amp;rsquo;t need to escape the SVG tags for my use case rendered in Firefox.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;With that, we now have the ability to inline SVGs in CSS.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/how-to-embed-svg-in-css</id>
<link href="https://erikarow.land/notes/how-to-embed-svg-in-css" />
<title>How to Embed an SVG in CSS</title>
<updated>2024-05-15T00:00:00+00:00</updated>
<dc:date>2024-05-15T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;How-to-Count-Unique-Lines-Using-Unix-Pipes&quot;&gt;
&lt;h1&gt;How to Count Unique Lines Using Unix Pipes&lt;/h1&gt;
&lt;p&gt;Sometimes I want to take a command line output and count the unique lines from that output. I can do this with a combination of standard unix tools and pipes:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html&quot;&gt;&lt;code&gt;sort&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/html_node/uniq-invocation.html&quot;&gt;&lt;code&gt;uniq&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/html_node/head-invocation.html&quot;&gt;&lt;code&gt;head&lt;/code&gt;&lt;/a&gt; in the linked GNU docs.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Alternatively, use &lt;code&gt;man sort&lt;/code&gt;, etc. to see what the available flags are on your system of choice.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I always find new things when I read the docs. &lt;code&gt;sort&lt;/code&gt; for example, has a &lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html#index-_002d_002dbatch_002dsize&quot;&gt;&lt;code&gt;--batch-size&lt;/code&gt;&lt;/a&gt; flag that limits the maximum number of inputs to be merged at once.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Hillel Wayne advocates for this kind of &amp;ldquo;browsing&amp;rdquo; documentation instead of &amp;ldquo;searching&amp;rdquo; in &lt;a href=&quot;https://buttondown.email/hillelwayne/archive/search-less-browse-more-7595/&quot;&gt;his newsletter&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;output&amp;gt; | sort | uniq -c | sort -nr | head -n 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using the long flag names, we can get a better sense of what&amp;rsquo;s going on:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I generally prefer long flags, because I tend to forget which shortflag goes to what. Especially if I haven&amp;rsquo;t used a particular command in a while. On my system, bash provides tab-completion for these long-flags, which makes them easier to discover and type.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;output&amp;gt; | sort \ 
  | uniq --count \ 
  | sort --numeric-sort --reverse \
  | head --lines 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step by step:&lt;/p&gt;
&lt;p&gt;First, we sort the output alphabetically with &lt;code&gt;sort&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, &lt;code&gt;uniq --count&lt;/code&gt; merges matching lines while prepending the count to each line.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;We needed to sort first because this merge only happens on identical lines next to each other in the output.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Then, &lt;code&gt;sort --numeric-sort --reverse&lt;/code&gt; sorts these lines by the prepended count, in descending order.&lt;/p&gt;
&lt;p&gt;Finally, we use &lt;code&gt;head --lines 5&lt;/code&gt; to only get the top 5 counts.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I see this as the unix equivalent to the SQL: &lt;code&gt;select count(field) from table group by field order by count(field) desc limit 5&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;Applications&quot;&gt;
&lt;h2&gt;Applications&lt;/h2&gt;
&lt;p&gt;I wanted to share a few places where I&amp;rsquo;ve found this useful recently. This technique combines well with other command line &amp;ldquo;power tools&amp;rdquo;, such as &lt;code&gt;awk&lt;/code&gt; and &lt;code&gt;jq&lt;/code&gt;:&lt;/p&gt;
&lt;section id=&quot;Cut---Aggregate-a-CSV-Column&quot;&gt;
&lt;h3&gt;Cut - Aggregate a CSV Column&lt;/h3&gt;
&lt;p&gt;If I have a csv like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hi,1,a
hello,2,a
world,3,b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can use &lt;code&gt;cut&lt;/code&gt; to select just a single column:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;code&gt;cut&lt;/code&gt; &lt;a href=&quot;https://www.gnu.org/software/coreutils/manual/html_node/cut-invocation.html&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I was originally going to use &lt;code&gt;awk&lt;/code&gt; for this example. Thanks to PgSuper for suggesting to use the simpler &lt;code&gt;cut&lt;/code&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;The original &lt;code&gt;awk&lt;/code&gt; is: &lt;code&gt;awk &#x27;BEGIN { FS = &quot;,&quot; } ; { print $3 }&#x27;&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Alternatively, &lt;code&gt;cut -d&#x27;,&#x27; -f3&lt;/code&gt; using the shortflags.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat my.csv \
  | cut --delimiter &#x27;,&#x27; --field 3 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, I can combine this output with our aggregation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;previous&amp;gt;  | sort | uniq -c | sort -nr | head -n 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get our aggregated count:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      2 a
      1 b
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;jq---Aggregating-the-Web&quot;&gt;
&lt;h3&gt;jq - Aggregating the Web&lt;/h3&gt;
&lt;p&gt;Our count unique aggregation works well with &lt;code&gt;jq&lt;/code&gt; for counting API output.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I tend to prefer &lt;a href=&quot;https://github.com/01mf02/jaq&quot;&gt;&lt;code&gt;jaq&lt;/code&gt;&lt;/a&gt;, a clone of &lt;code&gt;jq&lt;/code&gt;, for performance reasons, but &lt;code&gt;jq&lt;/code&gt; is the more popular tool. Both work with the same syntax from this example.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For example, Codeberg&amp;rsquo;s Forgejo instance exposes a public API with information about the repos hosted there:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;By default &lt;code&gt;/repos/search&lt;/code&gt; returns 25 items, at time of writing.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl &quot;https://codeberg.org/api/v1/repos/search&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can use &lt;code&gt;jq&lt;/code&gt; to turn the resulting JSON into a list of primary languages used on each repo:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Learn more about &lt;code&gt;jq&lt;/code&gt; from the &lt;a href=&quot;https://jqlang.github.io/jq/tutorial/&quot;&gt;tutorial&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;previous&amp;gt; | jq &#x27;.data[].language&#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I use &lt;code&gt;jq&lt;/code&gt; to access the &lt;code&gt;data&lt;/code&gt; key, operate over a list of objects, and then select the &lt;code&gt;language&lt;/code&gt; key from each one.&lt;/p&gt;
&lt;p&gt;Finally, we can aggregate to see what languages are most used:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;previous&amp;gt;  | sort | uniq -c | sort -nr | head -n 15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For me that looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      9 &quot;&quot;
      4 &quot;Shell&quot;
      4 &quot;Lua&quot;
      2 &quot;Python&quot;
      2 &quot;Markdown&quot;
      1 &quot;Kotlin&quot;
      1 &quot;HTML&quot;
      1 &quot;GDScript&quot;
      1 &quot;Emacs Lisp&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It looks like a fair number of repos don&amp;rsquo;t have their &lt;code&gt;language&lt;/code&gt; field set in the Forgejo API response.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/count-unique-unix</id>
<link href="https://erikarow.land/notes/count-unique-unix" />
<title>How to Count Unique Lines Using Unix Pipes</title>
<updated>2024-04-26T00:00:00+00:00</updated>
<dc:date>2024-04-26T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;I-created-a-little-webring-in-Gleam&quot;&gt;
&lt;h1&gt;I created a little webring in Gleam&lt;/h1&gt;
&lt;p&gt;Recently, my friends have been building cool web 1.0 features for their websites, such as &lt;a href=&quot;https://proclamations.nebcorp-hias.com/sundries/hitman/&quot;&gt;this hit counter&lt;/a&gt;. 
Inspired by web 1.0, 
I decided to create a web ring for me and my friends.&lt;/p&gt;
&lt;section id=&quot;What-is-a-webring&quot;&gt;
&lt;h2&gt;What is a webring?&lt;/h2&gt;
&lt;p&gt;A webring is a way of adding discoverability for sites in the ring.&lt;/p&gt;
&lt;p&gt;On a technical level, it&amp;rsquo;s a doubly linked list of websites&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Diagram made with &lt;a href=&quot;https://mermaid.live/&quot;&gt;mermaid.live&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;webring example with three websites all pointing to each other&quot; src=&quot;/webring.svg&quot;&gt;&lt;/p&gt;
&lt;p&gt;Each website links to the next and previous website in the linked list, 
creating a &amp;ldquo;ring&amp;rdquo; of websites that are all connected.&lt;/p&gt;
&lt;p&gt;In theory, it&amp;rsquo;s possible to literally link to the next site in the ring, but this quickly becomes impractical as member sites join or leave the ring. The solution is to write a little webring service:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;How-do-you-run-a-webring-service&quot;&gt;
&lt;h2&gt;How do you run a webring service?&lt;/h2&gt;
&lt;p&gt;Instead of having member sites link directly to each other, a webring service can handle routing each &amp;ldquo;next&amp;rdquo; and &amp;ldquo;previous&amp;rdquo; link to the appropriate place.&lt;/p&gt;
&lt;p&gt;At its core, this service consists of three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
A way to identify where someone accessing the service is in the ring.
&lt;/li&gt;
&lt;li&gt;
A &lt;code&gt;/previous&lt;/code&gt; endpoint to route people to the previous ring member.
&lt;/li&gt;
&lt;li&gt;
A &lt;code&gt;/next&lt;/code&gt; endpoint to route people to the next ring member.
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The endpoints can be powered by a simple HTTP 303 &amp;ldquo;See Other&amp;rdquo; redirect&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about that &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections&quot;&gt;here&lt;/a&gt; on the MDN documentation.&lt;/span&gt;&lt;/span&gt;, so the hard part is figuring out where you are in the ring and what next and previous member sites are.&lt;/p&gt;
&lt;section id=&quot;Where-are-you-ringing-from&quot;&gt;
&lt;h3&gt;Where are you ringing from?&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve seen a few different ways to keep track of which member site the webring is being accessed from&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Another thing I considered was a &lt;code&gt;from=&amp;lt;website&amp;gt;&lt;/code&gt; query parameter, but then I would have to worry about appropriately escaping web domains.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
An integer member number
&lt;/li&gt;
&lt;li&gt;
A short hash id
&lt;/li&gt;
&lt;li&gt;
Emojis&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Here&amp;rsquo;s a &lt;a href=&quot;https://martymcgui.re/2023/04/26/bad-web-dev-ideas-emoji-as-ids-in-urls/&quot;&gt;blog post&lt;/a&gt; from the person who runs the Indieweb Ring about why Emoji IDs are problematic in practice.&lt;/span&gt;&lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of these, I decided to use short hash ids, unique to each member site. I chose to use a SHA256 hash of the members URL, converted to padded, URL-safe base64 with a known salt&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Therefore, each member site only has to keep track of its own hash_id, and it&amp;rsquo;s designed not to change as members join or leave the ring.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn hash(string) {
  {string &amp;lt;&amp;gt; &quot;salty salt&quot;}
  |&amp;gt; bit_array.from_string()
  |&amp;gt; glesha.hash(glesha.Sha256)
  |&amp;gt; bit_array.base64_url_encode(True)
  |&amp;gt; string.slice(0, 16)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ll come back to how I used these hashes in a moment. First, we need to know who our neighbors in the ring are!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Ringing-my-neighbors&quot;&gt;
&lt;h3&gt;Ringing my neighbors&lt;/h3&gt;
&lt;p&gt;Starting from a list of member URLs, how do I turn them into a ring?&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It turns out that neither of the popular webrings that first come to my mind solve this problem.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://xn--sr8hvo.ws/&quot;&gt;An Indieweb Webring&lt;/a&gt; just picks a random link every time as detailed at the bottom of &lt;a href=&quot;https://martymcgui.re/2023/04/26/bad-web-dev-ideas-emoji-as-ids-in-urls/&quot;&gt;this blog post&lt;/a&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://webring.xxiivv.com/&quot;&gt;Devine&amp;rsquo;s webring&lt;/a&gt; just links to the index. This is nice because it means you only need to have one symbol/link on your website instead of &lt;code&gt;previous/next&lt;/code&gt; links.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;One thing I considered was using Zippers&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to my friend Hayleigh for suggesting I think about Zippers.&lt;/span&gt;&lt;/span&gt;, a functional programming technique for traversing data structures such as lists and trees.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Sourceror, an AST manipulation library for Elixir uses Zippers, and has &lt;a href=&quot;https://hexdocs.pm/sourceror/zippers.html&quot;&gt;an excellent guide&lt;/a&gt; to them.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;However, I don&amp;rsquo;t care so much about traversing the list quickly, so much as finding the immediate neighbors of each member. This reminded me of the &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html#window&quot;&gt;&lt;code&gt;list.window&lt;/code&gt;&lt;/a&gt; function in the Gleam standard library.&lt;/p&gt;
&lt;p&gt;In particular, this example looks close to what I need:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;window([1,2,3,4,5], 3)
// -&amp;gt; [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function is missing the neighbors for &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt;, but otherwise is doing what I need.
Looking at the implementation gives us this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn do_window(
  acc: List(List(a)), 
  l: List(a), 
  n: Int
) -&amp;gt; List(List(a)) {
  let window = take(l, n)

  case length(window) == n {
    True -&amp;gt; 
      do_window([window, ..acc], drop(l, 1), n)
    False -&amp;gt; acc
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function is asking: &amp;ldquo;Starting at the current element, what are the next &lt;code&gt;n-1&lt;/code&gt; elements after it?&amp;rdquo;
Returning the list if there aren&amp;rsquo;t enough elements. But I tack on the first few elements when &lt;code&gt;length(window) &amp;lt; n&lt;/code&gt; I&amp;rsquo;ll get what I need.
With some optimizations to avoid &lt;code&gt;length&lt;/code&gt; (which is an &lt;code&gt;O(n)&lt;/code&gt; check in Gleam&amp;rsquo;s Erlang target), I get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn do_window(acc, l, original) {
  let window = list.take(l, 3)

  case window {
    [a, b, c, ..] -&amp;gt;
      do_window(
        [
          Row(
            b, 
            hash(b), 
            previous: a, 
            next: c
          ), 
        ..acc
        ], 
        list.drop(l, 1), 
        original
      )
    ... // omitted
    [] -&amp;gt; acc
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since I&amp;rsquo;m already traversing the list, I go ahead and save the hash of each member while I&amp;rsquo;m there.&lt;/p&gt;
&lt;p&gt;Now that I&amp;rsquo;ve computed all the neighbors, I can cache them into a Sqlite database. 
Member links are going to be read far more often than there will be changes in membership, so this caching is useful. 
It also allows us to index the field with the hash, giving us a faster than &lt;code&gt;O(n)&lt;/code&gt; read time for links.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Constellation&quot;&gt;
&lt;h3&gt;Constellation&lt;/h3&gt;
&lt;p&gt;All together I&amp;rsquo;ve separated this caching logic into its own project: &lt;a href=&quot;https://git.kittencollective.com/erika/constellation&quot;&gt;Constellation&lt;/a&gt;.
This is just a webring for me and my friends, so I&amp;rsquo;m okay with manually running Constellation when I need to change membership.&lt;/p&gt;
&lt;p&gt;Constellation reads from a &lt;code&gt;members.txt&lt;/code&gt; that contains one member URL per line, computes the hashes and neighbors, and then creates a &lt;code&gt;members.db&lt;/code&gt; which I can &lt;code&gt;rsync&lt;/code&gt; to my server for use with the web service.&lt;/p&gt;
&lt;p&gt;Now how does that web service work?&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;A-Gleaming-Webring-Service&quot;&gt;
&lt;h2&gt;A Gleaming Web(ring) Service&lt;/h2&gt;
&lt;p&gt;Gleam&amp;rsquo;s web framework is &lt;a href=&quot;https://hexdocs.pm/wisp/&quot;&gt;Wisp&lt;/a&gt; which proved quite capable for my little webring.&lt;/p&gt;
&lt;p&gt;There are a number of examples in the Wisp repo. My webring is only a little more than a fancy router, so I started from the routing example.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Literally, you can see in &lt;a href=&quot;https://git.kittencollective.com/erika/ring/commit/ba8d256143a7bb76e7ee7ef7a5e578cb5ca4212b&quot;&gt;my second commit&lt;/a&gt; that I forgot to change the readme.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Gleam doesn&amp;rsquo;t have any macros, which makes routing exactly pattern matching. Or as the comment in the example puts it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Wisp doesn&amp;rsquo;t have a special router abstraction, instead we recommend using
regular old pattern matching. This is faster than a router, is type safe,
and means you don&amp;rsquo;t have to learn or be limited by a special DSL.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That gives my webring a router that looks like this&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Since routing is just pattern matching, even complex web applications in Gleam use nested case statements or functions that contain fine grained pattern matching.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn handle_request(req: Request) -&amp;gt; Response {
  use req &amp;lt;- web.middleware(req)

  case wisp.path_segments(req) {
    [hash, &quot;previous&quot;] -&amp;gt; handle_previous(hash)
    [hash, &quot;next&quot;] -&amp;gt; handle_next(hash)

    _ -&amp;gt; wisp.not_found()
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;handle_previous&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn handle_previous(hash) {
  let db_path = &quot;members.db&quot;
  use conn &amp;lt;- sqlight.with_connection(db_path)

  let previous =
    sqlight.query(
      &quot;select previous from ring where hash = ?&quot;,
      on: conn,
      with: [sqlight.text(hash)],
      expecting: dynamic.element(0, dynamic.string),
    )

  case previous {
    Ok([previous_link]) -&amp;gt; 
      wisp.redirect(previous_link)
    _ -&amp;gt; wisp.not_found()
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s a lot going on in this function.&lt;/p&gt;
&lt;p&gt;We have a &lt;code&gt;use&lt;/code&gt; statement, which allows the function to close the database connection when it&amp;rsquo;s done.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Here&amp;rsquo;s the &lt;a href=&quot;https://tour.gleam.run/advanced-features/use-sugar/&quot;&gt;language tour&lt;/a&gt; section on use sugar for more explanation.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Sqlite doesn&amp;rsquo;t know anything about Gleam types, so I use &lt;code&gt;sqlight.text&lt;/code&gt; to let Sqlite know what type I&amp;rsquo;m passing in.&lt;/p&gt;
&lt;p&gt;Gleam is statically typed, but we don&amp;rsquo;t know what type we&amp;rsquo;re going to get from the database&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn12&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn12&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Especially with Sqlite, the authors of &lt;a href=&quot;https://sqlite.org/flextypegood.html&quot;&gt;The Advantages of Flexible Typing&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;. 
The &lt;code&gt;dynamic&lt;/code&gt; module from the standard library allows us to 
write a simple parser to convert what the database returns into types that Gleam understands.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn13&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn13&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I &lt;a href=&quot;https://git.kittencollective.com/erika/ring/commit/c7d629645c15798e0f4652eaddef22f41984b597&quot;&gt;initially&lt;/a&gt; wrote more boilerplate than I needed, but I realized that I could simplify the parsers.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Wisp has a built in function &lt;a href=&quot;https://hexdocs.pm/wisp/wisp.html#redirect&quot;&gt;&lt;code&gt;wisp.redirect&lt;/code&gt;&lt;/a&gt; that handles the HTTP 303 redirects that I need.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Up-And-Running&quot;&gt;
&lt;h2&gt;Up And Running&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s it, after a similar &lt;code&gt;handle_next&lt;/code&gt; function, I put up the service behind &lt;a href=&quot;https://caddyserver.com/&quot;&gt;Caddy&lt;/a&gt; on a small server. If everything is working correctly, then it should be linked at the bottom of this article.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn14&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn14&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;For Desktop users, it should also be under my intro blurb at the top-left of the article.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The source code for the web service is &lt;a href=&quot;https://git.kittencollective.com/erika/ring&quot;&gt;here&lt;/a&gt;. Special thanks to Joe and Sara for inspiring me to write a webring. Here&amp;rsquo;s to making the internet a little cozier.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Extra-Goodies&quot;&gt;
&lt;h2&gt;Extra Goodies&lt;/h2&gt;
&lt;p&gt;At this point in the explanation, the webring does everything it needs in order to be a &lt;code&gt;ring&lt;/code&gt;, but we added a few extra features to make it shine:&lt;/p&gt;
&lt;section id=&quot;Random-Endpoint&quot;&gt;
&lt;h3&gt;Random Endpoint&lt;/h3&gt;
&lt;p&gt;Shortly after I got the webring up and running, I got a feature (and pull!) request to add a &amp;ldquo;random&amp;rdquo; feature.&lt;/p&gt;
&lt;p&gt;Adding it to the router was simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn handle_request(req: Request) -&amp;gt; Response {
  use req &amp;lt;- web.middleware(req)

  case wisp.path_segments(req) {
    [] -&amp;gt; home_page(req)

    [&quot;random&quot;] -&amp;gt; handle_random() // One line!

    [hash, &quot;previous&quot;] -&amp;gt; handle_previous(hash)
    [hash, &quot;next&quot;] -&amp;gt; handle_next(hash)

    _ -&amp;gt; wisp.not_found()
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the &lt;code&gt;handle_random&lt;/code&gt; function itself takes advantage of Sqlite&amp;rsquo;s &lt;code&gt;ORDER BY RANDOM()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select next from ring order by random() limit 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise the redirection works exactly the same as &lt;code&gt;handle_previous&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;A-Lustrous-Home-Page&quot;&gt;
&lt;h3&gt;A Lustrous Home Page&lt;/h3&gt;
&lt;p&gt;I wanted to have something for people to see when they navigated to &lt;a href=&quot;https://webring.club&quot;&gt;https://webring.club&lt;/a&gt;, the root domain of my webring.&lt;/p&gt;
&lt;p&gt;Getting the members was a simple &lt;code&gt;select member from ring&lt;/code&gt; SQL query:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let db_path = &quot;members.db&quot;
use conn &amp;lt;- sqlight.with_connection(db_path)
let members =
  sqlight.query(
    &quot;select member from ring order by member asc&quot;,
    on: conn,
    with: [],
    expecting: dynamic.element(0, dynamic.string),
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I chose to use &lt;a href=&quot;https://hexdocs.pm/lustre/&quot;&gt;Lustre&lt;/a&gt; for html templating.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn15&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn15&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I wrote about Lustre for interactive frontend before in &lt;a href=&quot;/notes/gleam-vite&quot;&gt;Embedding Gleam in my blog with Vite&lt;/a&gt;. Lustre also offers backend templating.&lt;/span&gt;&lt;/span&gt; Lustre&amp;rsquo;s elements are just functions, so I can use them in a &lt;code&gt;list.map&lt;/code&gt; over the members:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let members =
  result.unwrap(members, [])
  |&amp;gt; list.map(fn(member) {
    html.li(
      [], 
      [html.a(
          [attribute.href(member)], 
          [html.text(member)]
       )]
    )
  })

let html =
  html.body([], [
    html.h1(
      [], 
      [html.text(&quot;The Constellation Webring&quot;)]
    ),
    html.ul([], members),
  ])
  |&amp;gt; element.to_document_string_builder()
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/gleam-webring</id>
<link href="https://erikarow.land/notes/gleam-webring" />
<title>I created a little webring in Gleam</title>
<updated>2024-03-31T00:00:00+00:00</updated>
<dc:date>2024-03-31T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;My-Favorite-Gleam-Feature&quot;&gt;
&lt;h1&gt;My Favorite Gleam Feature&lt;/h1&gt;
&lt;p&gt;I found myself liking Gleam&amp;rsquo;s syntax more than any other language that I&amp;rsquo;ve used.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;With the specific exception of Elixir, where many of these insights took root. I chose to focus this article on Gleam, but both Elixir and Gleam share this feature.&lt;/span&gt;&lt;/span&gt; This article follows the path of logic as I tried to unravel why.&lt;/p&gt;
&lt;p&gt;My journey to understanding started with a simple question:&lt;/p&gt;
&lt;p&gt;Why are Gleam&amp;rsquo;s functions backwards compared to Erlang and Python? Specifically, why are the arguments to Gleam&amp;rsquo;s &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html#map&quot;&gt;&lt;code&gt;list.map&lt;/code&gt;&lt;/a&gt; in reverse order as compared Erlang&amp;rsquo;s &lt;a href=&quot;https://www.erlang.org/doc/man/lists#map-2&quot;&gt;&lt;code&gt;lists.map&lt;/code&gt;&lt;/a&gt;?&lt;/p&gt;
&lt;section id=&quot;Reverse-Order&quot;&gt;
&lt;h2&gt;Reverse Order&lt;/h2&gt;
&lt;p&gt;Gleam&amp;rsquo;s &lt;code&gt;list.map&lt;/code&gt; has the following signature:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Slightly simplified. The &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html#map&quot;&gt;actual signature&lt;/a&gt; has a &lt;code&gt;with&lt;/code&gt; &lt;a href=&quot;https://gleam.run/book/tour/functions.html#labelled-arguments&quot;&gt;label&lt;/a&gt; on the function argument, which allows for &lt;code&gt;list.map([1,2,3], with: fn(x) { x + 1})&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn map(list: List(a), fun: fn(a) -&amp;gt; b) -&amp;gt; List(b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gleam takes a &lt;code&gt;List&lt;/code&gt; as its first argument, and a function to map over the list, second.&lt;/p&gt;
&lt;p&gt;By contrast, here is the signature of Erlang&amp;rsquo;s &lt;code&gt;lists.map&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;map(Fun, List1) -&amp;gt; List2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Erlang takes a function as the first argument and a list as the second argument.&lt;/p&gt;
&lt;p&gt;Similarly, Python&amp;rsquo;s &lt;a href=&quot;https://docs.python.org/3/library/functions.html#map&quot;&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/a&gt; looks the same way:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Technically, the return type hint in Python3 would look different, but for the sake of expediency, I&amp;rsquo;m using &lt;code&gt;-&amp;gt; iterator&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python3&quot;&gt;map(function, iterator) -&amp;gt; iterator
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to understand why Gleam is backwards, we need to understand why Erlang and Python are forwards. Why are Erlang&amp;rsquo;s and Python&amp;rsquo;s functions arranged that way?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Partial-Application&quot;&gt;
&lt;h2&gt;Partial Application&lt;/h2&gt;
&lt;p&gt;Haskell shows a justification for why they&amp;rsquo;re created that way.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;And it is the other way, Haskell&amp;rsquo;s &lt;a href=&quot;https://hackage.haskell.org/package/base-4.19.0.0/docs/Prelude.html#v:map&quot;&gt;&lt;code&gt;map&lt;/code&gt;&lt;/a&gt; is arranged like Erlang&amp;rsquo;s.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In Haskell, all functions are implicitly curried. That is, they&amp;rsquo;re secretly all functions that take one argument and return other functions.&lt;/p&gt;
&lt;p&gt;This makes it easy to partially apply a function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;mapPlusOne = map (+1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I&amp;rsquo;ve created a &lt;code&gt;mapPlusOne&lt;/code&gt; function that takes a list of numbers and returns a list of those numbers with 1 added to them. Haskell&amp;rsquo;s currying means that I can accomplish this by simply putting the two functions next to each other.&lt;/p&gt;
&lt;p&gt;In this way, &lt;code&gt;map&lt;/code&gt; is &amp;ldquo;partially applied&amp;rdquo; and instead of getting back a list, I&amp;rsquo;ve created a useful function that I can reuse.&lt;/p&gt;
&lt;p&gt;Partial application is most useful when the most generic part of the function is set in the first argument, getting more specific as you go to the right.&lt;/p&gt;
&lt;p&gt;This makes it easy to &amp;ldquo;cut off&amp;rdquo; a function in a partially applied but generally useful state.&lt;/p&gt;
&lt;p&gt;By contrast, if &lt;code&gt;map&lt;/code&gt; was arranged like Gleam, then the partial application would be less useful:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;mapOnSpecificList = map [1,2,3] --insert function here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s far more likely that I&amp;rsquo;ll want to vary the input to a specific modification function, than to vary the modification function to a specific input. Data often changes more quickly than logic.&lt;/p&gt;
&lt;p&gt;Python is following in these footsteps and provides &lt;a href=&quot;https://docs.python.org/3/library/functools.html#functools.partial&quot;&gt;&lt;code&gt;functools.partial&lt;/code&gt;&lt;/a&gt; to accomplish similar things to Haskell:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;m editorializing a bit, &lt;code&gt;functools.partial&lt;/code&gt; wasn&amp;rsquo;t added to Python until &lt;a href=&quot;https://github.com/python/cpython/blob/main/Misc/HISTORY#L18905&quot;&gt;version 2.5 in 2006&lt;/a&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Python&amp;rsquo;s &lt;code&gt;map()&lt;/code&gt; &lt;em&gt;has&lt;/em&gt; always been explicitly for functional programming, as noted in the release notes for &lt;a href=&quot;https://github.com/python/cpython/blob/main/Misc/HISTORY#L33166C34-L33166C34&quot;&gt;Python 1.0.0&lt;/a&gt;: &amp;ldquo;New built-in functions &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt; and &lt;code&gt;reduce()&lt;/code&gt; perform standard functional programming operations&amp;rdquo;.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Interestingly, Lisp introduced a &lt;code&gt;mapList&lt;/code&gt; function in &lt;a href=&quot;https://www.softwarepreservation.org/projects/LISP/MIT/LISP_Prog_Man-Mar_1959.pdf/view&quot;&gt;1959&lt;/a&gt;, but it took the arguments in Gleam&amp;rsquo;s order: &lt;code&gt;mapList(L,f)&lt;/code&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Nearly every other language uses the &lt;code&gt;map(function, list)&lt;/code&gt; order, as shown on &lt;a href=&quot;https://en.wikipedia.org/wiki/Map_%28higher-order_function%29#Language_comparison&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;From this table, only Elixir, &lt;a href=&quot;https://en.wikipedia.org/wiki/Haxe&quot;&gt;Haxe&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/R_%28programming_language%29&quot;&gt;R&lt;/a&gt;, and &lt;a href=&quot;https://en.wikipedia.org/wiki/XQuery&quot;&gt;XQuery&lt;/a&gt; have non-method functions in Gleam&amp;rsquo;s order.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python3&quot;&gt;from functools import partial
map_plus_one = partial(map, lambda x: x + 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Erlang seems to have been influenced by the same ideas.&lt;/p&gt;
&lt;p&gt;Okay, now we understand why Erlang&amp;rsquo;s functions are the way they are, why are Gleam&amp;rsquo;s functions backwards?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Pipe-Operator&quot;&gt;
&lt;h2&gt;Pipe Operator&lt;/h2&gt;
&lt;p&gt;Gleam has a &lt;a href=&quot;https://gleam.run/book/tour/functions.html#pipe-operator&quot;&gt;pipe operator&lt;/a&gt; &lt;code&gt;|&amp;gt;&lt;/code&gt; that will take the value on the left, and try to pass it in as the first argument of the function on the right. It looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;[1,2,3] |&amp;gt; list.map(fn(x) { x + 1})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gleam&amp;rsquo;s &lt;code&gt;list.map&lt;/code&gt; takes two arguments, in the example above we&amp;rsquo;re able to write &lt;code&gt;list.map(fn(x) { x + 1})&lt;/code&gt; because the pipe operator is silently filling the first argument with the list on the left side. This becomes a bit clearer if we use Gleam&amp;rsquo;s capture operator syntax:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;As noted in the &lt;a href=&quot;https://gleam.run/book/tour/functions.html#function-capturing&quot;&gt;language tour&lt;/a&gt;, this is such a common operation that the former is simply a special shorthand for the latter.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In Elixir, the pipe operator is literally just a macro that takes &lt;code&gt;[1,2,3] |&amp;gt; a_function(other, args)&lt;/code&gt; and replaces it with &lt;code&gt;a_function([1,2,3], other, args)&lt;/code&gt; during compilation.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;[1,2,3] |&amp;gt; list.map(_, fn(x) { x + 1})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has the same effect as calling the function directly with that value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;list.map([1,2,3], fn(x) { x + 1})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pipe operator has the benefit of making data transformations more &amp;ldquo;sentence&amp;rdquo;-like. Since the operator moves left to right, a series of pipe operators can transform data in the same direction as native English speakers read language:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;[1,2,3] 
|&amp;gt; list.map(fn(x) { x + 1}) 
|&amp;gt; list.filter(fn(x) { x &amp;gt; 2 }) 
|&amp;gt; list.at(1) // Ok(4)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Haskell, by contrast (often)&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;It&amp;rsquo;s worth noting that Haskell has a left-to-right composition operator &lt;a href=&quot;https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Arrow.html#v:-62--62--62-&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/a&gt; and a reverse application operator which works like a pipe &lt;a href=&quot;https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Function.html#v:-38-&quot;&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/a&gt;, but in practice I don&amp;rsquo;t see it being used anywhere near as pervasively as the pipe operator in Gleam.&lt;/span&gt;&lt;/span&gt; ends up having a right to left flow to its logic. The specific details are finalized on the right, and then transformed by functions as the calls are made to the left:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Haskell&amp;rsquo;s equivalent to the &lt;code&gt;list.at&lt;/code&gt; function is the &lt;a href=&quot;https://hackage.haskell.org/package/base-4.19.0.0/docs/Prelude.html#v:-33--33-&quot;&gt;&lt;code&gt;!!&lt;/code&gt; operator&lt;/a&gt;. By default all operators in Haskell are infix, but they can be turned into prefix form by wrapping them in parentheses. In this case, I also partially apply &lt;code&gt;!!&lt;/code&gt; with index 1.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;code&gt;!!&lt;/code&gt; operator is different from &lt;code&gt;list.at&lt;/code&gt; in one way: Gleam&amp;rsquo;s version returns a result type, whereas Haskell&amp;rsquo;s version raises an error on an index missing from the list. I did find &lt;a href=&quot;https://hackage.haskell.org/package/relude-1.2.1.0/docs/Relude-List.html#v:maybeAt&quot;&gt;maybeAt&lt;/a&gt; which returns a &lt;code&gt;Maybe&lt;/code&gt;, Haskell&amp;rsquo;s version of result, but it&amp;rsquo;s in a library in not in Haskell&amp;rsquo;s standard library.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;(!! 1)
  . filter (&amp;gt;2)
  . map (+1)
  $ [1,2,3]
-- 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While I do love the pipe operator, we still haven&amp;rsquo;t answered the question: Why are Gleam&amp;rsquo;s functions backwards? To understand that, we need to explore another property of Gleam.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;method-like-functions&quot;&gt;
&lt;h2&gt;&amp;ldquo;method&amp;rdquo;-like functions&lt;/h2&gt;
&lt;p&gt;There are other languages that don&amp;rsquo;t have the pipe operator that do have this left to right directionality to data transformations.&lt;/p&gt;
&lt;p&gt;Method chaining gives us a similar ability to read transformations left to right. For example in Javascript:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn12&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn12&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot;&gt;Here&amp;rsquo;s&lt;/a&gt; the documentation for the Array &lt;code&gt;map&lt;/code&gt; method. The other two methods are similar.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;[1,2,3]
  .map(x =&amp;gt; { return x + 1})
  .filter(x =&amp;gt; { return x &amp;gt; 2})
  .at(1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So before, when I said that Gleam&amp;rsquo;s functions are backwards compared to Python, that was technically true. But in practice, methods are far more common in Python than functions. Python method signatures all begin with &lt;code&gt;self&lt;/code&gt;, similarly Rust&amp;rsquo;s methods also begin with &lt;code&gt;self&lt;/code&gt; as their first given argument.&lt;/p&gt;
&lt;p&gt;For example, Rust&amp;rsquo;s &lt;code&gt;Iterator.map&lt;/code&gt; method has this signature:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn13&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn13&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This signature has been simplified for clarity, you can confirm it against the real signature &lt;a href=&quot;https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn map&amp;lt;B, F&amp;gt;(self, f: F) -&amp;gt; Map&amp;lt;Self, F&amp;gt;
where
  F: Fn(Self::Item) -&amp;gt; B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It returns type &lt;code&gt;Map&lt;/code&gt; because it&amp;rsquo;s lazy, but otherwise the signature looks a lot like Gleam&amp;rsquo;s &lt;code&gt;list.map&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Looking more closely at Gleam, we see a similar pattern: all of the functions in &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html&quot;&gt;&lt;code&gt;gleam/list&lt;/code&gt;&lt;/a&gt; take a value of type &lt;code&gt;List&lt;/code&gt; as their first argument. And nearly all them return a &lt;code&gt;List&lt;/code&gt; allowing pipe operator &amp;ldquo;chaining&amp;rdquo; to happen. In this way, Gleam&amp;rsquo;s functions are &amp;ldquo;method&amp;rdquo;-like, in that their signatures line up with what we would expect from method signatures in Python or Rust.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn14&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn14&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The lack of this design in command line applications is part of why unix&amp;rsquo;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Xargs#Placement_of_arguments&quot;&gt;&lt;code&gt;xargs&lt;/code&gt;&lt;/a&gt; exists, to &amp;ldquo;fix&amp;rdquo; pipelines with the arguments the wrong way around.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;However, there is a substantial difference between Gleam and these method chaining languages: Gleam doesn&amp;rsquo;t have methods.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Lack-of-methods&quot;&gt;
&lt;h2&gt;Lack of methods&lt;/h2&gt;
&lt;p&gt;Gleam&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn15&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn15&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;And Elixir.&lt;/span&gt;&lt;/span&gt; doesn&amp;rsquo;t have methods. All functions are associated with modules, and not with specific data. This comes as a consequence of Gleam&amp;rsquo;s default immutability.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn16&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn16&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Gleam&amp;rsquo;s Erlang target allows you to manage state with living processes, and its Javascript target has support for &lt;a href=&quot;https://hexdocs.pm/gleam_javascript/gleam/javascript/array.html&quot;&gt;mutable arrays&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt; When I pass a list to &lt;code&gt;list.map&lt;/code&gt;, it returns a new list without mutating the original.&lt;/p&gt;
&lt;p&gt;This makes it easier to write functions that have referential transparency, which means that a function given the same inputs will always have the same output. This makes it easy to reason about Gleam code, since seeing the inputs and logic of the function is enough to see what the function is going to do.&lt;/p&gt;
&lt;p&gt;The net result of this lack of methods, is that the primary way to compose code in Gleam is to use the pipe operator.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn17&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn17&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There&amp;rsquo;s also the &lt;a href=&quot;https://gleam.run/book/tour/use.html&quot;&gt;&lt;code&gt;use&lt;/code&gt; expression&lt;/a&gt;, but that&amp;rsquo;s primarily syntax sugar for working with callbacks.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn18&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn18&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This lack of options is seems to be by design. Gleam has one happy path for doing things and not much room for alternate conventions. This ends up working in favor of my favorite feature.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So now Gleam has a pipe operator, and makes it the primary way to compose code, there&amp;rsquo;s one more quality of Gleam that enables my favorite feature:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;A-culture-of-qualified-imports&quot;&gt;
&lt;h2&gt;A culture of qualified imports&lt;/h2&gt;
&lt;p&gt;By default an &lt;a href=&quot;https://gleam.run/book/tour/modules.html#import&quot;&gt;&lt;code&gt;import&lt;/code&gt;&lt;/a&gt; declaration in a Gleam module is qualified. That means that instead of dumping the functions and types from the imported module into the the current module&amp;rsquo;s namespace, they&amp;rsquo;re accessible by prefixing the imported modules name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import other_module

pub fn main() {
  other_module.useful_function(...)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To prevent this prefixing from getting unwieldy, Gleam will use the last part of the import path as the namespace:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn19&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn19&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In Elixir, all modules are always available at their fully qualified name &lt;code&gt;Module.Path.Here&lt;/code&gt;, and you need to use the &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.SpecialForms.html#alias/2&quot;&gt;&lt;code&gt;alias&lt;/code&gt;&lt;/a&gt; macro in order to shorten that prefix.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;For example: &lt;code&gt;alias Module.Path.Here&lt;/code&gt; will allow that module to be used as &lt;code&gt;Here&lt;/code&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;I prefer Gleam&amp;rsquo;s design here.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn20&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn20&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In fact, Gleam forces you to use the shortened prefix: &lt;code&gt;gleam/list.map&lt;/code&gt; will raise an error. It does allow the &lt;a href=&quot;https://gleam.run/book/tour/modules.html#named-import&quot;&gt;&lt;code&gt;as&lt;/code&gt;&lt;/a&gt; keyword to rename this qualified import if there&amp;rsquo;s a conflict.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/list

pub fn main() {
  // instead of gleam/list.map
  [1,2,3] |&amp;gt; list.map(...)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gleam does allow for unqualified imports, where functions can be used directly the current modules namespace, but they must be enumerated explicitly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/list.{map, filter}

pub fn main() {
  [1,2,3]
  |&amp;gt; map(fn(x) { x + 1})
  |&amp;gt; filter(fn(x) { x &amp;gt; 2})
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, Gleam warns against unqualified imports in the &lt;a href=&quot;https://gleam.run/book/tour/modules.html#unqualified-import&quot;&gt;language tour&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This may be useful for values that are used frequently in a module, but generally qualified imports are preferred as it &lt;strong&gt;makes it clearer where the value is defined&lt;/strong&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn21&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn21&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Emphasis mine.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is the combination of these three factors: a language designed around pipe operator, a lack of methods in the language, and a culture of qualified imports that leads to my favorite feature of Gleam:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;My-Favorite-Feature-Discoverability&quot;&gt;
&lt;h2&gt;My Favorite Feature: Discoverability&lt;/h2&gt;
&lt;p&gt;As a consequence of these three factors working in combination, I can visibly see which modules each function in a data transformation pipeline come from. For example in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/list

[1,2,3]
|&amp;gt; list.map(...)
|&amp;gt; list.filter(...)
|&amp;gt; list.at(...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know where &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;at&lt;/code&gt; come from, and I can easily look up the documentation for &lt;a href=&quot;https://hexdocs.pm/gleam_stdlib/gleam/list.html&quot;&gt;&lt;code&gt;gleam/list&lt;/code&gt;&lt;/a&gt; to understand more about each function and what other functions are available. The implementation details of a function in Gleam are plain to see and easy to learn more about.&lt;/p&gt;
&lt;p&gt;So my favorite feature of Gleam, is that it&amp;rsquo;s discoverable. I can read someone else&amp;rsquo;s code and understand each every module that they chose to use, and where every function comes from.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn22&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn22&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In a language with method chaining, a Language Server grants you write-time discoverability. You can add a &lt;code&gt;.&lt;/code&gt; and hit tab, and discover all of the currently available methods.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;However, at read time, this discoverability is lost, making it hard to understand which trait or type or object or class implements the method that you&amp;rsquo;re currently dealing with.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Often classes will reuse method names, overloading a given term, and making harder to search for where that method is implemented.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This discoverability makes it a joy to read source code written in Gleam. I&amp;rsquo;ve improved as a software engineer as a consequence of being able to learn from the core libraries of my favorite language.&lt;/p&gt;
&lt;p&gt;Thank you to John, &lt;a href=&quot;https://theo-harris-dev.com&quot;&gt;Theodore&lt;/a&gt;, &lt;a href=&quot;https://ntietz.com/&quot;&gt;Nicole&lt;/a&gt;, &lt;a href=&quot;https://hachyderm.io/@jmeowmeow&quot;&gt;Jeff&lt;/a&gt;, Miccah, and &lt;a href=&quot;https://jakelazaroff.com&quot;&gt;Jake&lt;/a&gt; for helping me write and edit this article. And thank you to the Gleam discord for helping me validate some of these concepts.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/gleam-favorite-feature</id>
<link href="https://erikarow.land/notes/gleam-favorite-feature" />
<title>My Favorite Gleam Feature</title>
<updated>2024-01-08T00:00:00+00:00</updated>
<dc:date>2023-11-14T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Embedding-Gleam-in-my-blog-with-Vite&quot;&gt;
&lt;h1&gt;Embedding Gleam in my blog with Vite&lt;/h1&gt;
&lt;p&gt;My interest in &lt;a href=&quot;https://lustre.build/&quot;&gt;Gleam&lt;/a&gt; came primarily from the idea of having Erlang with Static types. Gleam is able to transpile to Javascript, so I wanted to try embedding it in my blog. I might want to add interactive explanations to my blog in the future, and it would be neat to be able to write them in Gleam.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Update 2024-01-06: I now recommend using &lt;code&gt;esgleam&lt;/code&gt; instead of &lt;code&gt;vite-gleam&lt;/code&gt;, which I&amp;rsquo;ve written about &lt;a href=&quot;/notes/esgleam-embed&quot;&gt;here&lt;/a&gt;. All the Gleam explanation still lives here, but the simplified deployment instructions are in the new blog post.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;Step-1-Create-Lustre-Project&quot;&gt;
&lt;h2&gt;Step 1: Create Lustre Project&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://lustre.build/&quot;&gt;Lustre&lt;/a&gt; is a frontend web framework for Gleam. It has an Elm-inspired runtime that makes it easy to create dynamic components with Gleam.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Lustre can also be used on the &lt;a href=&quot;https://lustre.build/docs/quickstart/#on-the-server&quot;&gt;server side&lt;/a&gt; as a HTML templating DSL.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I can create a new Gleam project with the CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gleam new shiny_counter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can then enter the newly created project folder and add Lustre:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd shiny_counter
gleam add lustre
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can start building my Lustre application.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://lustre.build/api/lustre/#simple&quot;&gt;simple&lt;/a&gt; Lustre application consists of an initialization function, an update function, and a view function.&lt;/p&gt;
&lt;section id=&quot;Init&quot;&gt;
&lt;h3&gt;Init&lt;/h3&gt;
&lt;p&gt;The initialization function is responsible for setting the initial state of the Lustre model.&lt;/p&gt;
&lt;p&gt;In my &lt;code&gt;shiny_counter&lt;/code&gt; it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;type Model =
  Int

fn init(_) -&amp;gt; Model {
  0
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I define the &lt;code&gt;Model&lt;/code&gt; to be just an integer, and initialize that integer to 0.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Update&quot;&gt;
&lt;h3&gt;Update&lt;/h3&gt;
&lt;p&gt;The update function takes a model and a message as arguments and returns an updated model based on the contents of that message.&lt;/p&gt;
&lt;p&gt;In the case of &lt;code&gt;shiny_counter&lt;/code&gt; I only need an increment and decrement message:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Since the model of &lt;code&gt;shiny_counter&lt;/code&gt; is an Integer, it&amp;rsquo;s signed, so if I send a &lt;code&gt;Decrement&lt;/code&gt; message enough times, I will get a negative number. If I wanted a model where I couldn&amp;rsquo;t produce a negative number, I would want to add extra cases into my update function.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type Msg {
  Increment
  Decrement
}

fn update(model: Model, msg: Msg) -&amp;gt; Model {
  case msg {
    Increment -&amp;gt; model + 1
    Decrement -&amp;gt; model - 1
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;View&quot;&gt;
&lt;h3&gt;View&lt;/h3&gt;
&lt;p&gt;The view function takes a model and returns a Lustre Element constructor that handles both communicating with the update function as well as rendering the contents of the view to HTML.&lt;/p&gt;
&lt;p&gt;In the case of &lt;code&gt;shiny_counter&lt;/code&gt;, I convert the current state of the model to a string, then I render that count as well as provide two buttons which send defined messages to update the model:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;view(model: Model) -&amp;gt; Element(Msg) {
  let count = int.to_string(model)

  html.div(
    [],
    [
      html.p([], [element.text(count)]),
      html.p(
        [],
        [
          html.button([event.on_click(Decrement)], [element.text(&quot;-&quot;)]),
          html.button([event.on_click(Increment)], [element.text(&quot;+&quot;)]),
        ],
      ),
    ],
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here, I can add &lt;a href=&quot;https://lustre.build/api/lustre/attribute/#style&quot;&gt;styling&lt;/a&gt; to make it live up to its &lt;code&gt;shiny_counter&lt;/code&gt; name. Here, I&amp;rsquo;ve added styling to center the text and added the all important ✨ emoji:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn view(model: Model) -&amp;gt; Element(Msg) {
  let count = int.to_string(model)

  html.div(
    [],
    [
      html.p(
        [attribute.style([#(&quot;text-align&quot;, &quot;center&quot;)])],
        [element.text(count &amp;lt;&amp;gt; &quot; ✨&quot;)],
      ),
      html.p(
        [attribute.style([#(&quot;text-align&quot;, &quot;center&quot;)])],
        [
          html.button([event.on_click(Decrement)], [element.text(&quot;-&quot;)]),
          html.button([event.on_click(Increment)], [element.text(&quot;+&quot;)]),
        ],
      ),
    ],
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Start-the-application&quot;&gt;
&lt;h3&gt;Start the application&lt;/h3&gt;
&lt;p&gt;Now that I&amp;rsquo;ve defined the key parts of a simple Lustre application, I need to combine them into an application. I do that with &lt;a href=&quot;https://lustre.build/api/lustre/attribute/#style&quot;&gt;&lt;code&gt;lustre.simple&lt;/code&gt;&lt;/a&gt; in this case, since &lt;code&gt;shiny_counter&lt;/code&gt; doesn&amp;rsquo;t have complex interactive behavior. Once I have the application, I can simply start it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn main() {
  let app = lustre.simple(init, update, view)
  let assert Ok(dispatch) = lustre.start(app, &quot;[gleam_example]&quot;, Nil)

  dispatch
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://lustre.build/api/lustre/#start&quot;&gt;&lt;code&gt;lustre.start&lt;/code&gt;&lt;/a&gt; starts an application anchored on an HTML element specified by a CSS selector. In this case &lt;code&gt;[gleam_example]&lt;/code&gt; finds an element that has the &lt;code&gt;gleam_example&lt;/code&gt; attribute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div gleam_example&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lustre will replace the selected element entirely with the running application after it loads.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;When I initially tried Lustre, the example I borrowed from used &lt;code&gt;&quot;body&quot;&lt;/code&gt; as the CSS selector, and completely wiped out the template of my blog, making it awfully hard to write this article.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;I could tell that I misconfigured Lustre, because my blog was briefly visible until the Javascript loaded. This blog post is about embedding Gleam in my blog, not replacing my blog with Gleam.&lt;/span&gt;&lt;/span&gt; In this case, I chose an attribute since it&amp;rsquo;s unlikely that I&amp;rsquo;ll have anything else on the page with that custom attribute.&lt;/p&gt;
&lt;p&gt;Now that I have a Lustre application that does what I want,
I need to embed it in my blog.&lt;/p&gt;
&lt;p&gt;While Gleam does transpile to Javascript it generates a number of different modules that are tedious to use in my static site generator. Enter Vite as a way to bundle the Javascript into a single file:&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Step-2-Install-and-configure-Vite&quot;&gt;
&lt;h2&gt;Step 2: Install and configure Vite&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt; is a Javascript bundling tool, it&amp;rsquo;s explicitly designed to transform Node libraries or other Javascript modules and make them easy to use in a browser.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Here&amp;rsquo;s a &lt;a href=&quot;https://paste.sr.ht/~erikareads/71002a37b32ecb211ecc6a375107cdf179f6e4ec&quot;&gt;link&lt;/a&gt; to the &lt;code&gt;shell.nix&lt;/code&gt; that I used for this project.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I can install Vite with &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;&lt;code&gt;npm&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install vite
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vite is designed for Javascript and not for Gleam, and so I need to rely on a plugin to show Vite where Gleam&amp;rsquo;s transpiled Javascript is. I can add that plugin with &lt;code&gt;npm&lt;/code&gt;:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to a member of the Gleam community for creating the &lt;a href=&quot;https://github.com/Enderchief/gleam-tools/tree/master/packages/vite-gleam&quot;&gt;&lt;code&gt;vite-gleam&lt;/code&gt;&lt;/a&gt; plugin.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm add vite-gleam
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that I&amp;rsquo;ve added &lt;code&gt;vite-gleam&lt;/code&gt; I can create a config file to use it:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;a href=&quot;https://rollupjs.org/configuration-options/#input&quot;&gt;&lt;code&gt;rollupOptions.input&lt;/code&gt;&lt;/a&gt; setting allows me to change the entry file for Vite. By default this is &lt;code&gt;index.html&lt;/code&gt;, but since I&amp;rsquo;m going to be using the bundled Javascript in this blog post, I don&amp;rsquo;t need a generated &lt;code&gt;index.html&lt;/code&gt; file. This setting is described in the &lt;a href=&quot;https://vitejs.dev/guide/backend-integration.html&quot;&gt;Backend Integration&lt;/a&gt; instructions for Vite.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;a href=&quot;https://rollupjs.org/configuration-options/#output-entryfilenames&quot;&gt;&lt;code&gt;output.entryFileNames&lt;/code&gt;&lt;/a&gt; setting allows me to precisely specify the name of the generated Javascript file. By default, the generated Javascript has a randomly generated name suitable for cache busting. Since I&amp;rsquo;m copying the generated Javascript file from my Gleam project into my static site generator, I wanted a specific filename to reference in the embedded &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import gleam from &quot;vite-gleam&quot;;

export default {
  plugins: [gleam()],
  build: {
    rollupOptions: {
      input: &#x27;main.js&#x27;,
      output: {
        dir: &#x27;./dist&#x27;,
        entryFileNames: &#x27;assets/gleam_vite_example.js&#x27;,
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I create a file called &lt;code&gt;main.js&lt;/code&gt; to act as the entry point for Vite:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { main } from &#x27;./src/shiny_counter.gleam&#x27;

document.addEventListener(&quot;DOMContentLoaded&quot;, () =&amp;gt; {
  const dispatch = main({});
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can finally call &lt;code&gt;vite build&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;By default, Gleam transpiles to Erlang, but &lt;code&gt;vite-gleam&lt;/code&gt; will use &lt;code&gt;--target javascript&lt;/code&gt; to generate the Javascript code before bundling.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you would like to transpile to Javascript without Vite, then set &lt;code&gt;target = &quot;javascript&quot;&lt;/code&gt; in the project&amp;rsquo;s &lt;code&gt;Gleam.toml&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;, this will use the &lt;code&gt;vite-gleam&lt;/code&gt; plugin to first transpile the Gleam code to Javascript, then it will use the &lt;code&gt;main.js&lt;/code&gt; entry point to bundle all of the modules into a single file named &lt;code&gt;gleam_vite_example.js&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Step-3-Use-the-bundled-Javascript-in-my-Static-Site&quot;&gt;
&lt;h2&gt;Step 3: Use the bundled Javascript in my Static Site&lt;/h2&gt;
&lt;p&gt;Now I can copy the Javascript from my Gleam project into my static site generator. Once there, I can add markup to my site to use it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/notes/djot&quot;&gt;Djot&lt;/a&gt;, the markup language that I use for my blog allows me to do an HTML passthrough block:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;```=html
&amp;lt;div style=&quot;border: 1px solid&quot;&amp;gt;
  &amp;lt;div gleam_example&amp;gt;
    &amp;lt;script type=&quot;module&quot; src=&quot;/assets/gleam_vite_example.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I&amp;rsquo;ve specified a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag with the &lt;code&gt;gleam_example&lt;/code&gt; attribute, added a script tag to use the bundled Gleam Javascript, and then wrapped both in a stylized div.&lt;/p&gt;
&lt;p&gt;As mentioned in Step 1, Lustre will replace the attributed div with the running Lustre application after it starts up, leaving me with an embedded interactive component.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Step-4-Publish&quot;&gt;
&lt;h2&gt;Step 4: Publish&lt;/h2&gt;
&lt;div style=&quot;margin-left:auto;margin-right:auto;border: 1px solid;display: table;width:40%;&quot;&gt;
  &lt;div gleam_example&gt;
    &lt;script type=&quot;module&quot; src=&quot;/assets/gleam_vite_example.js&quot;&gt;&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It works!&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You can see the source code for &lt;code&gt;shiny_counter&lt;/code&gt; &lt;a href=&quot;https://git.sr.ht/~erikareads/shiny_counter&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really neat that I can take Gleam and embed it directly into my blog posts. Thank you to everyone in the Gleam discord for helping me figure all of this out.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/gleam-vite</id>
<link href="https://erikarow.land/notes/gleam-vite" />
<title>Embedding Gleam in my blog with Vite</title>
<updated>2024-01-06T00:00:00+00:00</updated>
<dc:date>2023-11-18T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Embedding-Gleam-in-my-blog-with-esgleam&quot;&gt;
&lt;h1&gt;Embedding Gleam in my blog with esgleam&lt;/h1&gt;
&lt;p&gt;Previously in &lt;a href=&quot;/notes/gleam-vite&quot;&gt;Embedding Gleam in my blog with Vite&lt;/a&gt;, I used the &lt;code&gt;vite-gleam&lt;/code&gt; plugin to bundle my compiled Gleam JS and embed it into my blog. Since then, the creator of the &lt;code&gt;vite-gleam&lt;/code&gt; plugin has created &lt;a href=&quot;https://hexdocs.pm/esgleam/index.html&quot;&gt;&lt;code&gt;esgleam&lt;/code&gt;&lt;/a&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;As of the time of writing, the most recent version of &lt;code&gt;esgleam&lt;/code&gt; is 0.3.0.&lt;/span&gt;&lt;/span&gt; which allows me to bundle my Gleam JS without needing Node installed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;esgleam&lt;/code&gt; downloads &lt;code&gt;esbuild&lt;/code&gt; as a pre-built executable which acts as a bundler for my project&amp;rsquo;s javascript.&lt;/p&gt;
&lt;p&gt;I explained in detail how the Gleam application works in my &lt;a href=&quot;/notes/gleam-vite&quot;&gt;previous article&lt;/a&gt;, so I will focus on how &lt;code&gt;esgleam&lt;/code&gt; makes it easier for me to deploy here.&lt;/p&gt;
&lt;section id=&quot;esgleam&quot;&gt;
&lt;h2&gt;&lt;code&gt;esgleam&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Adding &lt;code&gt;esgleam&lt;/code&gt; to my &lt;code&gt;shiny_counter&lt;/code&gt; project was simple:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gleam add esgleam
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could then run &lt;code&gt;esgleam/install&lt;/code&gt; to download the &lt;code&gt;esbuild&lt;/code&gt; executable:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gleam run -m esgleam/install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then bundling the &lt;code&gt;shiny_counter&lt;/code&gt; Javascript was simple:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gleam run -m esgleam/bundle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default &lt;code&gt;esgleam&lt;/code&gt; finds my &lt;code&gt;src/shiny_counter.gleam&lt;/code&gt; and turns it into &lt;code&gt;dist/shiny_counter.js&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I found that the defaults were perfect for my needs, but &lt;code&gt;esgleam&lt;/code&gt; has an &lt;a href=&quot;https://hexdocs.pm/esgleam/index.html&quot;&gt;Advanced Usage&lt;/a&gt; which allows for specific customization of the bundling process.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;That was all I needed to do to bundle the Javascript for my project. Then all I needed were a few more steps to embed the Javascript in my project:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Embedding-the-Javascript&quot;&gt;
&lt;h2&gt;Embedding the Javascript&lt;/h2&gt;
&lt;p&gt;I then copied the &lt;code&gt;shiny_counter.js&lt;/code&gt; to my static sites assets folder. Unlike when I bundled with &lt;code&gt;vite&lt;/code&gt;, I didn&amp;rsquo;t have a &lt;code&gt;main.js&lt;/code&gt; that enabled the listener for the project, so I need to that manually here:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;As a reminder, the &lt;code&gt;gleam_example&lt;/code&gt; is a custom attribute which &lt;code&gt;shiny_counter&lt;/code&gt; is using a CSS selector to find and mount the Lustre application to.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;```=html
&amp;lt;div style=&quot;border: 1px solid&quot;&amp;gt;
  &amp;lt;div gleam_example&amp;gt;
  &amp;lt;script type=&quot;module&quot;&amp;gt; 
  import { main } from &#x27;/assets/shiny_counter.js&#x27;

  document.addEventListener(&quot;DOMContentLoaded&quot;, () =&amp;gt; {
    const dispatch = main({});
  });
  &amp;lt;/script&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which works!&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to &lt;a href=&quot;https://github.com/Enderchief&quot;&gt;Enderchief&lt;/a&gt; for creating &lt;code&gt;esgleam&lt;/code&gt; to simplify the deployment story for Gleam browser Javascript!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;margin-left:auto;margin-right:auto;border: 1px solid;display: table;width:40%;&quot;&gt;
  &lt;div gleam_example&gt;
  &lt;script type=&quot;module&quot;&gt; 
  import { main } from &#x27;/assets/shiny_counter.js&#x27;

  document.addEventListener(&quot;DOMContentLoaded&quot;, () =&gt; {
    const dispatch = main({});
  });
  &lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/esgleam-embed</id>
<link href="https://erikarow.land/notes/esgleam-embed" />
<title>Embedding Gleam in my blog with esgleam</title>
<updated>2024-01-06T00:00:00+00:00</updated>
<dc:date>2024-01-06T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Using-Regex-in-Erlang&quot;&gt;
&lt;h1&gt;Using Regex in Erlang&lt;/h1&gt;
&lt;p&gt;Recently, I was helping someone port some code to Erlang that involved a Regex. I hadn&amp;rsquo;t worked with Regex in Erlang before, so here are some notes on what I learned.&lt;/p&gt;
&lt;section id=&quot;re---Perl-like-regular-expressions-for-Erlang&quot;&gt;
&lt;h2&gt;&lt;code&gt;re&lt;/code&gt; - Perl-like regular expressions for Erlang&lt;/h2&gt;
&lt;p&gt;The Erlang standard library has the &lt;a href=&quot;https://www.erlang.org/doc/man/re&quot;&gt;&lt;code&gt;re&lt;/code&gt;&lt;/a&gt; module, which supports regular expression matching for Erlang strings and binaries.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Both Gleam and Elixir use String to mean an Erlang binary. The default string type in Erlang is sugar over a linked list of code points.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;re&lt;/code&gt; module provides three main functions: &lt;code&gt;replace&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, and &lt;code&gt;split&lt;/code&gt;, which all operate on string-like input&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Erlang uses the &lt;a href=&quot;https://www.erlang.org/doc/man/erlang#type-iodata&quot;&gt;&lt;code&gt;iodata&lt;/code&gt;&lt;/a&gt; type to represent a generalization on binaries that can be more efficiently worked with, all three of these functions take an &lt;code&gt;iodata&lt;/code&gt; or &lt;a href=&quot;https://www.erlang.org/doc/man/unicode#type-charlist&quot;&gt;&lt;code&gt;charlist&lt;/code&gt;&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt; and a regex pattern.&lt;/p&gt;
&lt;p&gt;Regex matching can be done with &lt;code&gt;run&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;&amp;gt; re:run(&quot;my string&quot;, &quot;[myexpression]&quot;).
{match,[{0,1}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default &lt;code&gt;run&lt;/code&gt; returns all captured parts of the input, as a list of &lt;code&gt;{Offset, Length}&lt;/code&gt; pairs. It also only returns the first match, not all matches.&lt;/p&gt;
&lt;p&gt;To return the captures as strings, I can use the &lt;code&gt;{capture, all, list}&lt;/code&gt; option:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;&amp;gt; re:run(&quot;my string&quot;, 
    &quot;[myexpression]&quot;,
    [{capture, all, list}]
  ).
{match,[&quot;m&quot;]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get all of the matches, I can use the &lt;code&gt;global&lt;/code&gt; option:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;&amp;gt; re:run(&quot;my string&quot;, 
    &quot;[myexpression]&quot;,
    [global,{capture, all, list}]
  ).
{match,[[&quot;m&quot;],[&quot;y&quot;],[&quot;s&quot;],[&quot;r&quot;],[&quot;i&quot;],[&quot;n&quot;]]}
&lt;/code&gt;&lt;/pre&gt;
&lt;section id=&quot;Named-Captures&quot;&gt;
&lt;h3&gt;Named Captures&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;re&lt;/code&gt; supports Perl-style named captures, which look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;Pattern1 = &quot;(?&amp;lt;myname&amp;gt;capture)&quot;.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can used by changing the &lt;code&gt;ValueSpec&lt;/code&gt; component of the capture option:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There isn&amp;rsquo;t a built in way to associate names with captures. Elixir provides a &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Regex.html#named_captures/3&quot;&gt;&lt;code&gt;named_captures&lt;/code&gt;&lt;/a&gt; function to easily do this.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;From reading the &lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/v1.12.3/lib/elixir/lib/regex.ex#L354&quot;&gt;source code&lt;/a&gt; of the Elixir implementation, it should be possible to combine &lt;code&gt;re:inspect&lt;/code&gt; with &lt;code&gt;lists:zip&lt;/code&gt; to get a list of &lt;code&gt;{Name, Capture}&lt;/code&gt; pairs.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;&amp;gt; re:run(
    &quot;my capture of my capture&quot;, 
    Pattern1, 
    [
      global,
      {capture, [&quot;myname&quot;], list}
    ]
  ).
{match,[[&quot;capture&quot;],[&quot;capture&quot;]]}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Compiling-An-Expression&quot;&gt;
&lt;h3&gt;Compiling An Expression&lt;/h3&gt;
&lt;p&gt;Erlang provides a &lt;a href=&quot;https://www.erlang.org/doc/man/re#compile-2&quot;&gt;&lt;code&gt;compile&lt;/code&gt;&lt;/a&gt; function to compile a regular expression for re-use throughout the lifetime of a program:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Compiling the regular expression before matching is useful if the same expression is to be used in matching against multiple subjects during the lifetime of the program. Compiling once and executing many times is far more efficient than compiling each time one wants to match.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A regex can be compiled into a pattern for use with &lt;a href=&quot;https://www.erlang.org/doc/man/re#compile-2&quot;&gt;&lt;code&gt;compile&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;{ok, Pattern2} = re:compile(&quot;[myexpression]&quot;).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The used like any other regex pattern:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;&amp;gt; re:run(
    &quot;my string&quot;,
    Pattern2,
    [{capture, all, list}]
  ).
{match,[&quot;m&quot;]}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;The Erlang regular expression module is a bit difficult to use, but it will be nice if I have need of a zero-dependency regex module when using Erlang.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/using-erlang-re</id>
<link href="https://erikarow.land/notes/using-erlang-re" />
<title>Using Regex in Erlang</title>
<updated>2023-12-07T00:00:00+00:00</updated>
<dc:date>2023-12-07T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Tools-I-Use-codespell&quot;&gt;
&lt;h1&gt;Tools I Use: codespell&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/codespell-project/codespell&quot;&gt;codespell&lt;/a&gt; is a command line spellcheck tool that is code-aware. Codespell allows me to spellcheck my software projects without getting stuck on all the jargon that software projects use.&lt;/p&gt;
&lt;section id=&quot;Usage-and-Tips&quot;&gt;
&lt;h2&gt;Usage and Tips&lt;/h2&gt;
&lt;p&gt;I often use codespell to spellcheck the markup for this blog. It&amp;rsquo;s nice to have a tool that doesn&amp;rsquo;t get stuck on the code blocks I use in my articles.&lt;/p&gt;
&lt;p&gt;It does occasionally get caught on rarer words or words that have more common English spellings for example, running it on my site&amp;rsquo;s markup folder gives me this:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Unconfigured. My configuration later in the article fixes this.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content/notes/crate-reqwest.dj:1: Crate ==&amp;gt; Create
content/notes/crate-reqwest.dj:4: Crate ==&amp;gt; Create
content/notes/crate-surf.dj:1: Crate ==&amp;gt; Create
content/notes/crate-surf.dj:4: Crate ==&amp;gt; Create
content/notes/bookmarks/2023-07-20.dj:149: simpy ==&amp;gt; simply
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both &amp;ldquo;Crate&amp;rdquo; and &amp;ldquo;simpy&amp;rdquo; are correct, the former is a legitimate English word, and the latter is a part of a URL.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;As confirmed by Wikitionary: &lt;a href=&quot;https://en.wiktionary.org/wiki/crate#Noun&quot;&gt;crate&lt;/a&gt;. Which specifically has a definition for the Rust usage.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This catch on &amp;ldquo;crate&amp;rdquo; is because of the default dictionary option, which is set to &lt;code&gt;clear,rare&lt;/code&gt;. This behavior can be modified with the &lt;code&gt;--builtin clear&lt;/code&gt; option to only show errors on unambiguous errors.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;As such, while &lt;code&gt;codespell&lt;/code&gt; has a &lt;code&gt;--write-changes&lt;/code&gt; flag, I would caution against its use in a non-interactive mode.&lt;/p&gt;
&lt;section id=&quot;Interactive&quot;&gt;
&lt;h3&gt;Interactive&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;codespell&lt;/code&gt; does allow for interactive updates with a combination of flags:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;codespell &amp;lt;optional_folder&amp;gt; --interactive 1 --write-changes
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Ignore-words&quot;&gt;
&lt;h3&gt;Ignore words&lt;/h3&gt;
&lt;p&gt;Another option is to use the &lt;code&gt;--ignore-words-list&lt;/code&gt; option, which takes a comma separated list of words to ignore:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;codespell &amp;lt;optional_folder&amp;gt; --ignore-words-list crate,simpy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have enough words to make passing them as a comma separated list unwieldy,
then you can use &lt;code&gt;--ignore-words&lt;/code&gt; to pass a file with each word on its own line.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Config&quot;&gt;
&lt;h2&gt;Config&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;codespell&lt;/code&gt; will look for a &lt;code&gt;.codespellrc&lt;/code&gt; file in the local directory for configuration.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Despite mentioning toml in the &lt;a href=&quot;https://github.com/codespell-project/codespell#using-a-config-file&quot;&gt;README&lt;/a&gt;, the configuration format is not toml. Which took me a bit to figure out. toml only seems to apply if you configure it with &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;The default configuration format seems to be closer to an &lt;code&gt;ini&lt;/code&gt; format.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve set my config for this site like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[codespell]
builtin = clear
ignore-words-list = simpy
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;codespell&lt;/code&gt; is a neat little tool for spellchecking in a code heavy environment. I use it regularly to spellcheck these articles. I use few of its additional features or options, just a simple, effective command-line spellchecking tool.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/tools-use-codespell</id>
<link href="https://erikarow.land/notes/tools-use-codespell" />
<title>Tools I Use: codespell</title>
<updated>2023-12-04T00:00:00+00:00</updated>
<dc:date>2023-12-04T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Serve-a-Static-Directory-with-Erlang&quot;&gt;
&lt;h1&gt;Serve a Static Directory with Erlang&lt;/h1&gt;
&lt;p&gt;For a long time, I&amp;rsquo;ve been serving static files to locally test this website using &lt;code&gt;python3 -m http.server&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Actually, I used a custom script that overrode the &lt;code&gt;Handler&lt;/code&gt; class to set the mimetype for files without an extension to &lt;code&gt;&quot;text/html&quot;&lt;/code&gt;, since I use that to get clean urls without &lt;code&gt;.html&lt;/code&gt; on the end.&lt;/span&gt;&lt;/span&gt; I&amp;rsquo;ve wanted to do this with Erlang for a long time, after I found out that Erlang has a built in &lt;a href=&quot;https://www.erlang.org/doc/apps/inets/http_server&quot;&gt;&lt;code&gt;httpd&lt;/code&gt; server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Recently, I found out&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thank you to someone on the &lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt; discord who pointed this out to me!&lt;/span&gt;&lt;/span&gt; that a short command like the python one will be added in &lt;a href=&quot;https://github.com/erlang/otp/pull/7299&quot;&gt;OTP 27&lt;/a&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Investigating the origin of the pull request, I found &lt;a href=&quot;https://gist.github.com/willurd/5720255&quot;&gt;this list&lt;/a&gt; of &amp;ldquo;serve this directory of static files&amp;rdquo; commands across a variety of languages. If Erlang isn&amp;rsquo;t your jam, enjoy!&lt;/span&gt;&lt;/span&gt;. Soon you will be able to invoke &lt;code&gt;erl -S httpd&lt;/code&gt; to serve static files locally. Looking at the &lt;a href=&quot;https://github.com/erlang/otp/pull/7299/files#diff-d8239d05391b50fc317f0ce1f9ea048a8011210ebd3361e31f60e379c970fe13&quot;&gt;diff&lt;/a&gt; I was able to write an Elixir script that serves a static directory for me now.&lt;/p&gt;
&lt;section id=&quot;The-Script&quot;&gt;
&lt;h2&gt;The Script&lt;/h2&gt;
&lt;p&gt;The core of the script is powered by &lt;code&gt;:httpd.start_service/1&lt;/code&gt; which takes a proplist of settings that configure the httpd server. I always found the list of configuration options intimidating, so I was glad to have a place to start with from the diff.&lt;/p&gt;
&lt;section id=&quot;Required-Property&quot;&gt;
&lt;h3&gt;Required Property&lt;/h3&gt;
&lt;p&gt;Four properties are required:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[
  {:port, 8008},
  {:server_name, &#x27;localhost&#x27;},
  {:server_root, absolute_path},
  {:document_root, absolute_path}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
All string properties need to be single-quoted Elixir charlists, because &lt;code&gt;:httpd&lt;/code&gt; is expecting Erlang strings, not Elixir binaries.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;From the Elixir &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/List.html#module-charlists&quot;&gt;documentation&lt;/a&gt;: &amp;ldquo;The rationale behind this behaviour is to better support Erlang libraries which may return text as charlists instead of Elixir strings.&amp;rdquo;&lt;/span&gt;&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
I had to set &lt;code&gt;:server_name&lt;/code&gt; to exactly &lt;code&gt;&#x27;localhost&#x27;&lt;/code&gt;, in order to get my websites relative links to work correctly. So far I can tell, I can run multiple versions of &lt;code&gt;:httpd&lt;/code&gt; on different ports with the same name without issue.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;absolute_path&lt;/code&gt;, like the diff, I used an absolute_path path generated using some Erlang functions instead of a local path, but I believe a relative path would work.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:server_root&lt;/code&gt; is the root directory that all other properties are relative to.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:document_root&lt;/code&gt; is what I actually want to serve my static files.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Additional-Properties&quot;&gt;
&lt;h3&gt;Additional Properties&lt;/h3&gt;
&lt;p&gt;I also set some additional properties for my needs:&lt;/p&gt;
&lt;section id=&quot;bind_address&quot;&gt;
&lt;h4&gt;&lt;code&gt;:bind_address&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The default value is set to &lt;code&gt;:any&lt;/code&gt;, I specifically set mine to &lt;code&gt;{127, 0, 0, 1}&lt;/code&gt;. I think this would be the same as the &lt;code&gt;:any&lt;/code&gt; behavior, but better safe than sorry.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;mime_types&quot;&gt;
&lt;h4&gt;&lt;code&gt;:mime_types&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Like I did with Python, I was able to set the mimetype for no extension to &lt;code&gt;text/html&lt;/code&gt; by adding &lt;code&gt;{&#x27;&#x27;, &#x27;text/html&#x27;}&lt;/code&gt; to my list of mimetypes, which I otherwise took from the diff.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;default_type&quot;&gt;
&lt;h4&gt;&lt;code&gt;:default_type&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;This undocumented&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;a href=&quot;https://www.erlang.org/doc/man/httpd#prop_mime_type&quot;&gt;documentation&lt;/a&gt; says to use &lt;code&gt;mime_type&lt;/code&gt;, but I found that when I set this to &lt;code&gt;&#x27;text/html&#x27;&lt;/code&gt;, my extensionless files still were rendered as plain text. After investigation, I found that &lt;code&gt;mime_type&lt;/code&gt; &lt;a href=&quot;https://github.com/erlang/otp/issues/7827&quot;&gt;does nothing&lt;/a&gt; and hasn&amp;rsquo;t since at least OTP-17.0.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;code&gt;default_type&lt;/code&gt; property does do what &lt;code&gt;mime_type&lt;/code&gt; claims, but isn&amp;rsquo;t mentioned in the documentation.&lt;/span&gt;&lt;/span&gt; property sets the default mimetype for files that don&amp;rsquo;t match the existing &lt;code&gt;:mime_types&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;directory_index&quot;&gt;
&lt;h4&gt;&lt;code&gt;:directory_index&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Idiosyncratically, I use &lt;code&gt;home&lt;/code&gt; instead of &lt;code&gt;index.html&lt;/code&gt; for my folder indexes on my website, Erlang easily let me set this with &lt;code&gt;{:directory_index, [&#x27;home&#x27;]}&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I don&amp;rsquo;t remember where I picked this up from, but I&amp;rsquo;ve used in my last 3 static site generators.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;modules&quot;&gt;
&lt;h4&gt;&lt;code&gt;:modules&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;:httpd&lt;/code&gt; comes with a number of &lt;a href=&quot;https://www.erlang.org/doc/apps/inets/http_server#inets-web-server-modules&quot;&gt;modules&lt;/a&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;There&amp;rsquo;s a &lt;code&gt;mod_trace&lt;/code&gt; module that enables support for the TRACE request type. I didn&amp;rsquo;t know these existed, but apparently they&amp;rsquo;re included in HTTP/1.1. It&amp;rsquo;s even listed on &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE&quot;&gt;MDN&lt;/a&gt;!?&lt;/span&gt;&lt;/span&gt; to extend its behavior. For my script, I enabled the same three as the diff:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:mod_alias&lt;/code&gt;, I believe this enables the directory index behavior.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:mod_dir&lt;/code&gt;, will generate an Apache style file listing, if a directory index isn&amp;rsquo;t found, though this shouldn&amp;rsquo;t apply for my website.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:mod_get&lt;/code&gt;, which enables GET requests for regular files, which is what I want to a static directory being served.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Other-Details&quot;&gt;
&lt;h3&gt;Other Details&lt;/h3&gt;
&lt;section id=&quot;inetsstart0&quot;&gt;
&lt;h4&gt;&lt;code&gt;:inets.start/0&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;:inets&lt;/code&gt; service must be started before &lt;code&gt;:httpd&lt;/code&gt; can work. So my script includes a call to &lt;code&gt;:inets.start()&lt;/code&gt; before &lt;code&gt;:httpd.start_service/1&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;no-halt&quot;&gt;
&lt;h4&gt;&lt;code&gt;no-halt&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;:inets&lt;/code&gt; &lt;a href=&quot;https://www.erlang.org/doc/apps/inets/http_server#getting-started&quot;&gt;Getting Started&lt;/a&gt; suggests that after starting &lt;code&gt;:inets&lt;/code&gt;, you can start an &lt;code&gt;:httpd&lt;/code&gt; server by calling &lt;code&gt;:inets.start(:httpd, config)&lt;/code&gt;. This does start a httpd server, but in my script it immediately ended because the main process no longer had any work.&lt;/p&gt;
&lt;p&gt;I can avoid this behavior by passing &lt;code&gt;--no-halt&lt;/code&gt; when calling my script, but I chose to mimic the diff, by setting up a &lt;code&gt;receive do&lt;/code&gt; which blocks until it receives a message that the server is down. This gives the same effect, without needing to pass additional arguments on invocation.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m glad to hear that Erlang is soon going to get the ability to quickly and easily host a static directory like Python. If you&amp;rsquo;re interested in this ability now, I&amp;rsquo;ve put my script &lt;a href=&quot;https://paste.sr.ht/~erikareads/72a9c6c9c77731bfe2945c1a9984b9ad0af668f6&quot;&gt;here&lt;/a&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you would prefer the escript, I&amp;rsquo;ve created that &lt;a href=&quot;https://paste.sr.ht/~erikareads/fb242336227367307acc88cbb721d1ef114b44ef&quot;&gt;here&lt;/a&gt;. I prefer the Elixir syntax, but the escript version has the benefit of only needing Erlang to run.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/erlang-serve-static-directory</id>
<link href="https://erikarow.land/notes/erlang-serve-static-directory" />
<title>Serve a Static Directory with Erlang</title>
<updated>2023-11-06T00:00:00+00:00</updated>
<dc:date>2023-11-06T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Always-Show-Scrollbars-in-Firefox-and-Thunderbird&quot;&gt;
&lt;h1&gt;Always Show Scrollbars in Firefox (and Thunderbird)&lt;/h1&gt;
&lt;p&gt;I use the scrollbar to gauge how far I&amp;rsquo;ve read through an article or webpage. But the default of hiding the scrollbar after a few moments makes this frustrating.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Prior to figuring out how to do this, I would wiggle the mouse over the bar every time I wanted to check. This quickly became frustrating.&lt;/span&gt;&lt;/span&gt; Firefox has a setting for this, which makes the scrollbar always visible.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Credit to &lt;a href=&quot;https://superuser.com/questions/1720362/firefox-scroll-bar-disappearing&quot;&gt;this&lt;/a&gt; Stack Overflow answer for pointing me to the setting.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In Firefox 116, I can find this setting in Settings -&amp;gt; General -&amp;gt; Browsing -&amp;gt; &amp;ldquo;Always show scrollbars&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of Firefox&amp;rsquo;s setting page showing a checked box for Always Show Scrollbars&quot; src=&quot;/firefox_scrollbar_example.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;After enabling this setting, the scrollbar is always visible on pages long enough to need one, with a backdrop that visually distinguishes it from the webpage.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note that this blog post might not be long enough to show you a scrollbar.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;Thunderbird&quot;&gt;
&lt;h2&gt;Thunderbird&lt;/h2&gt;
&lt;p&gt;Thunderbird (version 102) has an equivalent setting: &lt;br&gt;
Settings -&amp;gt; General -&amp;gt; Language &amp;amp; Appearance -&amp;gt; Scrolling -&amp;gt; &amp;ldquo;Always show scrollbars&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Similar to Firefox, when this setting is enabled it will always show a scrollbar on anything long enough to need one, with a backdrop to visually distinguish it.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/firefox-always-show-scrollbar</id>
<link href="https://erikarow.land/notes/firefox-always-show-scrollbar" />
<title>Always Show Scrollbars in Firefox (and Thunderbird)</title>
<updated>2023-11-05T00:00:00+00:00</updated>
<dc:date>2023-11-02T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;When-is-an-Erlang-process-a-shell&quot;&gt;
&lt;h1&gt;When is an Erlang process a shell?&lt;/h1&gt;
&lt;p&gt;Recently, I was trying to port an Erlang function to Elixir,
with the goal of answering one question: &amp;ldquo;When is an Erlang process a shell?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Answering that question involved source diving Erlang, learning new &lt;a href=&quot;/notes/git-checkout-tag&quot;&gt;things about git&lt;/a&gt;, and reading mailing lists.&lt;/p&gt;
&lt;section id=&quot;The-Original-Code&quot;&gt;
&lt;h2&gt;The Original Code&lt;/h2&gt;
&lt;p&gt;The code I wanted to port was this function&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Erlang&amp;rsquo;s syntax might seem a bit weird if you haven&amp;rsquo;t been exposed to it before. Erlang was originally &lt;a href=&quot;https://en.wikipedia.org/wiki/Erlang_%28programming_language%29%23History&quot;&gt;implemented in prolog&lt;/a&gt;, which inspired much of the syntax.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Variables in Erlang are &lt;code&gt;UpperCase&lt;/code&gt;, which makes them easy to pick out of code once you&amp;rsquo;re used to it, but opposite of the norm in Algol inspired languages.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;The Prolog inspiration also led to a &amp;ldquo;sentence-like&amp;rdquo; structure, with commas, semicolons, and periods. Note that this function end with a &lt;code&gt;.&lt;/code&gt; character.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;is_shell(ProcessId) -&amp;gt;
  case erlang:process_info(ProcessId, group_leader) of
    undefined -&amp;gt; false; %% process is dead
    {group_leader, Leader} -&amp;gt;
      case lists:keyfind(shell, 1, group:interfaces(Leader)) of
        {shell, ProcessId} -&amp;gt; true;
        {shell, Shell} -&amp;gt;
          case erlang:process_info(Shell, dictionary) of
            {dictionary, Dict} -&amp;gt;
              proplists:get_value(evaluator, Dict) =:= ProcessId;
            undefined -&amp;gt; false %% process is dead
          end;
        false -&amp;gt; false
      end
  end.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can follow along here, we&amp;rsquo;re retrieving something called &lt;code&gt;group_leader&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Erlang and Elixir have the concept of atoms. Atoms are equal to only themselves, and their value is exactly their name. This seems pretty useless until you consider pattern matching.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;I can use a pattern like &lt;code&gt;{:my_atom, value}&lt;/code&gt; to match on the &lt;code&gt;:my_atom&lt;/code&gt; as a key and assign the second tuple item to the variable &lt;code&gt;value&lt;/code&gt;.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note that in Elixir atoms are typically denoted with a prefixed colon, like &lt;code&gt;:this&lt;/code&gt;. In Erlang, atoms are lower case with no other markings, like &lt;code&gt;this&lt;/code&gt;, which works because variables are upper case in Erlang.&lt;/span&gt;&lt;/span&gt; from the process&amp;rsquo;s metadata. The equivalent function call in Elixir would be &lt;code&gt;Process.info(pid, :group_leader)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What is a group_leader? There was sparse information about group leaders in the Erlang documentation, but I found a mailing thread response that said this:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note, the original source uses outdated terminology for &lt;code&gt;origin&lt;/code&gt; and &lt;code&gt;peer&lt;/code&gt;, the &lt;code&gt;peer&lt;/code&gt; module superseded the previous module in &lt;a href=&quot;https://www.erlang.org/news/157#erts-stdlib-kernel&quot;&gt;OTP 25.0&lt;/a&gt;. Original source &lt;a href=&quot;https://erlang.org/pipermail/erlang-questions/2018-April/095179.html&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Group leaders let you redirect I/O to the right endpoint. It is one of 
the few properties that is inherited by one process to the other, 
creating a chain.&lt;/p&gt;
&lt;p&gt;By default, an Erlang node has one group leader called &amp;lsquo;user&amp;rsquo;. This 
process owns communication with the stdio channels, and all input 
requests and output messages transit through that one.&lt;/p&gt;
&lt;p&gt;Then, each shell you start becomes its own group leader. This means that 
any function you run from the shell will send all its IO data to that 
shell process.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A group leader gives us a sense of where each process belongs to, and since each shell has its own group leader &lt;code&gt;is_shell/1&lt;/code&gt; needs to unpack this information to find whether it&amp;rsquo;s a shell.&lt;/p&gt;
&lt;p&gt;This answers the question about group leaders, the next curiosity in the function is &lt;code&gt;group:interfaces&lt;/code&gt; which is called on the group leader process id.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;groupinterfaces&quot;&gt;
&lt;h2&gt;&lt;code&gt;group:interfaces&lt;/code&gt;!?&lt;/h2&gt;
&lt;p&gt;So the first thing I did was to extract the group leader of my Elixir IEx shell, and try to call &lt;code&gt;:group.interfaces&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In this story I&amp;rsquo;m switching back and forth between Erlang and Elixir syntax. Know that &lt;code&gt;module:function/arity&lt;/code&gt; in Erlang is equivalent to &lt;code&gt;:module.function/arity&lt;/code&gt; in Elixir.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Elixir has first class support for calling Erlang functions, and this manifests as similar but subtly different syntax.&lt;/span&gt;&lt;/span&gt; on that process id.&lt;/p&gt;
&lt;p&gt;Just one problem, IEx raises an &lt;code&gt;UndefinedFunctionError&lt;/code&gt;, telling me that it doesn&amp;rsquo;t exist. That&amp;rsquo;s okay, it&amp;rsquo;s been 11 years since the Erlang code was written, perhaps that function was taken out.&lt;/p&gt;
&lt;p&gt;So the next thing I try is to repeat the same experiment directly in the Erlang shell &lt;code&gt;erl&lt;/code&gt;. I open a new terminal, invoke &lt;code&gt;erl&lt;/code&gt;, get the &lt;code&gt;erlang:process_info(self(), group_leader).&lt;/code&gt; I pass this process id to &lt;code&gt;group:interfaces(GroupLeaderPid).&lt;/code&gt;, and I get a valid list of interfaces!?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m confused for a short while, before remembering that I use &lt;code&gt;nix-shell&lt;/code&gt; to manage my Elixir version. So when I ran the &lt;code&gt;:group.interfaces&lt;/code&gt; invocation in IEx, it was in OTP 26, &lt;code&gt;erts-14.1&lt;/code&gt;. However, when I ran &lt;code&gt;group:interfaces&lt;/code&gt; in &lt;code&gt;erl&lt;/code&gt;, it was in OTP 25, &lt;code&gt;erts-13.2.2&lt;/code&gt;. Something must have changed in the &lt;code&gt;group&lt;/code&gt; module between OTP 25 and OTP 26.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;erts&lt;/code&gt; stands for the Erlang Run-Time System Application. Erlang versions its applications separately from the OTP as a whole, leading to the two version numbers I shared.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Git-Spelunking&quot;&gt;
&lt;h2&gt;Git Spelunking&lt;/h2&gt;
&lt;p&gt;In order to figure out what what was going with &lt;code&gt;group&lt;/code&gt; I needed to turn back time.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Jeff for the turn of phrase.&lt;/span&gt;&lt;/span&gt; &lt;code&gt;group&lt;/code&gt; is an internal module in Erlang, and lacks external documentation. So I needed to explore the source code directly.&lt;/p&gt;
&lt;p&gt;Thankfully, &lt;code&gt;git&lt;/code&gt; gives us an easy way to &lt;a href=&quot;git-checkout-tag&quot;&gt;checkout old code&lt;/a&gt;. Running &lt;code&gt;git checkout OTP-25.0&lt;/code&gt; on the &lt;a href=&quot;https://github.com/erlang/otp/&quot;&gt;&lt;code&gt;otp&lt;/code&gt; repository&lt;/a&gt; drops me into the OTP code as it was at that release.&lt;/p&gt;
&lt;p&gt;A quick ripgrep for &lt;code&gt;interfaces/1&lt;/code&gt; leads me to &lt;code&gt;lib/kernel/src/group.erl&lt;/code&gt; and &lt;code&gt;interfaces/1&lt;/code&gt;:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In the middle of this process, I confused &lt;code&gt;user_drv:interfaces&lt;/code&gt; with &lt;code&gt;group:interfaces&lt;/code&gt; and convinced myself that it had mysteriously changed from a function that didn&amp;rsquo;t do what I needed to a function that worked between OTP 25.0 and OTP 25.3. I had no basis for why this change might have happened or why it happened so late after the function was created, when it&amp;rsquo;s clear that 11 years ago in the function that starts this article, it was used in the same way as OTP 25.3.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Specifically, I think I got lost because I had backgrounded my text editor in &lt;code&gt;user_drv.erl&lt;/code&gt;, and when I checked out &lt;code&gt;OTP 25.0&lt;/code&gt; the &lt;code&gt;interfaces&lt;/code&gt; function appeared.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;interfaces(Group) -&amp;gt;
    case process_info(Group, dictionary) of
	{dictionary,Dict} -&amp;gt;
	    get_pids(Dict, [], false);
	_ -&amp;gt;
	    []
    end.

get_pids([Drv = {user_drv,_} | Rest], Found, _) -&amp;gt;
    get_pids(Rest, [Drv | Found], true);
get_pids([Sh = {shell,_} | Rest], Found, Active) -&amp;gt;
    get_pids(Rest, [Sh | Found], Active);
get_pids([_ | Rest], Found, Active) -&amp;gt;
    get_pids(Rest, Found, Active);
get_pids([], Found, true) -&amp;gt;
    Found;
get_pids([], _Found, false) -&amp;gt;
    [].
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;interfaces&lt;/code&gt; it first extracts the process dictionary&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Joe Armstrong in his book, &amp;ldquo;Programming Erlang, 2nd Edition&amp;rdquo; says this: &amp;ldquo;Each process in Erlang has its own private data store called the process dictionary. The process dictionary is an associative array (in other languages this might be called a map, hashmap, or hash table) composed of a collection of keys and values. Each key has only one value.&amp;rdquo;&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;He continues: &amp;ldquo;Note: I rarely use the process dictionary. Using the process dictionary can introduce subtle bugs into your program and make it difficult to debug.&amp;rdquo;&lt;/span&gt;&lt;/span&gt; then it tail recursively extract tuples that contain &lt;code&gt;user_drv&lt;/code&gt; or &lt;code&gt;shell&lt;/code&gt; as their first element.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Erlang has ad-hoc polymorphism, which it uses here in &lt;code&gt;get_pids&lt;/code&gt; to succinctly pattern match on the shape of the arguments passed in.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In our original function, we only care about the &lt;code&gt;shell&lt;/code&gt;, but otherwise I now knew enough to port &lt;code&gt;is_shell/1&lt;/code&gt; into Elixir:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Port-of-function-into-Elixir&quot;&gt;
&lt;h2&gt;Port of function into Elixir&lt;/h2&gt;
&lt;p&gt;In this version, I skipped past implementing &lt;code&gt;interfaces&lt;/code&gt; and simply pulled the &lt;code&gt;:shell&lt;/code&gt; key out of the process dictionary of the group leader:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In Elixir it&amp;rsquo;s convention to add a &lt;code&gt;?&lt;/code&gt; to the name of a function that returns a boolean.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Joe Armstrong&amp;rsquo;s comment about the process dictionary implies that it is a keyword list, but most of the Erlang functions I see interacting with it treat it as a &lt;code&gt;proplist&lt;/code&gt;. These two data structures are similar, both are built on top of the Erlang list.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;A keyword list, is a list of 2-tuples, with the first element being an atom key, and the second being a value for the key. A keyword list is a valid proplist, but a proplist has a shortcut where an atom key by itself stands in for &lt;code&gt;{atom, true}&lt;/code&gt;, this breaks all of Elixir&amp;rsquo;s Keyword functions, that presume a well-formed keyword list.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Keyword List Example: &lt;code&gt;[{:key1, &quot;value&quot;}, {:key2, 5}, {:key3, true}]&lt;/code&gt;&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Proplist Example: &lt;code&gt;[{:key1, &quot;value&quot;}, {:key2, 5}, :key3]&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn12&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn12&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;In this code snippet, I use the pin operator &lt;code&gt;^&lt;/code&gt;. In Erlang, variables can only be assigned once, so after their first assignment, you can use them to pattern match.&lt;/span&gt;&lt;span class=&quot;footnote-p&quot;&gt;Elixir allows variable shadowing, meaning that you can reuse a variable name. In order to do pattern matching on a variable&amp;rsquo;s contents, instead of reassigning it, Elixir added the pin operator &lt;code&gt;^&lt;/code&gt; to &amp;ldquo;pin&amp;rdquo; the value of the variable for the pattern match. Learn more &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.SpecialForms.html#%5E/1&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def is_shell?(pid) do
  case Process.info(pid, :group_leader) do
    :undefined -&amp;gt;
      false

    {:group_leader, leader} -&amp;gt;
      {:dictionary, leader_dict} = Process.info(leader, :dictionary)

      case :proplists.get_value(:shell, leader_dict) do
        ^pid -&amp;gt;
          true

        shell when is_pid(shell) -&amp;gt;
          case Process.info(shell, :dictionary) do
            {:dictionary, dict} -&amp;gt;
              :proplists.get_value(:evaluator, dict) === pid

            :undefined -&amp;gt;
              false
          end

        :undefined -&amp;gt;
          false
      end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Refactor-to-use-with&quot;&gt;
&lt;h2&gt;Refactor to use &lt;code&gt;with&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The nested &lt;code&gt;case&lt;/code&gt; statements in the previous function can be refactored using Elixir&amp;rsquo;s &lt;code&gt;with&lt;/code&gt; statement for a cleaner function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def is_shell?(pid) do
  with {:group_leader, leader} &amp;lt;- Process.info(pid, :group_leader),
       {:dictionary, leader_dict} &amp;lt;- Process.info(leader, :dictionary),
       {:shell, ^pid} &amp;lt;- :lists.keyfind(:shell, 1, leader_dict) do
    true
  else
    {:shell, shell} -&amp;gt;
      with {:dictionary, dict} &amp;lt;- Process.info(shell, :dictionary) do
        :proplists.get_value(:evaluator, dict) === pid
      else
        _ -&amp;gt; false
      end

    _ -&amp;gt;
      false
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Shell-improvements-OTP-26&quot;&gt;
&lt;h2&gt;Shell improvements OTP 26&lt;/h2&gt;
&lt;p&gt;Earlier, I found that &lt;code&gt;group:interfaces/1&lt;/code&gt; was missing from OTP 26. This seems to be connected to the &lt;a href=&quot;https://www.erlang.org/blog/otp-26-highlights/#the-shell&quot;&gt;OTP 26 shell improvements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth looking at &lt;code&gt;group:whereis_shell/0&lt;/code&gt; as a comparison with my &lt;code&gt;is_shell?/1&lt;/code&gt; function:&lt;/p&gt;
&lt;section id=&quot;groupwhereis_shell&quot;&gt;
&lt;h3&gt;&lt;code&gt;group:whereis_shell&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The OTP 26 implementation of &lt;code&gt;group:whereis_shell&lt;/code&gt; contains this snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;GroupPid -&amp;gt;
  {dictionary, Dict} = 
    erlang:process_info(GroupPid, dictionary),
  proplists:get_value(shell, Dict)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is nearly identical to my pre-&lt;code&gt;with&lt;/code&gt; refactor implementation in Elixir. Which means I&amp;rsquo;m probably on the right track.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;groupstart_shell1&quot;&gt;
&lt;h3&gt;&lt;code&gt;group:start_shell/1&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;I also wanted to call attention to this comment above &lt;code&gt;group:start_shell/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;%% start_shell(Shell)
%%  Spawn a shell with its group_leader from the beginning set to ourselves.
%%  If Shell [is] a pid the[n] set its group_leader.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which confirms what we learned earlier about group leaders and how they relate to shells.&lt;/p&gt;
&lt;p&gt;That would have been the end of the story, until I read the comment above the &lt;code&gt;is_shell/1&lt;/code&gt; function in the original codebase:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;%% Theoretically pman_process:is_system_process/1 should say true for
%% the shell.  Well, it doesn&#x27;t, so this is a workaround until it
%% does.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What is &lt;code&gt;pman_process&lt;/code&gt;? Unlike &lt;code&gt;:group.interfaces/1&lt;/code&gt;, the function isn&amp;rsquo;t missing, the module is gone. This led me down a rabbit hole that required learning &lt;a href=&quot;/notes/git-spelunking-bisect&quot;&gt;how to bisect a git repo&lt;/a&gt;:&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;What-is-pman_process&quot;&gt;
&lt;h2&gt;What is &lt;code&gt;:pman_process&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;A search for &amp;ldquo;Erlang pman&amp;rdquo; turns up a &lt;a href=&quot;https://erlang.org/documentation/doc-5.9/lib/pman-2.7.1.1/doc/html/pman_chapter.html&quot;&gt;process viewing tool&lt;/a&gt; from an ancient version of Erlang. The screenshots of the interface look like they&amp;rsquo;re right out of &lt;a href=&quot;https://en.wikipedia.org/wiki/Twm&quot;&gt;Tab Window Manager&lt;/a&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn13&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn13&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I briefly used &lt;code&gt;twm&lt;/code&gt; when I used OpenBSD on the desktop, but I preferred &lt;a href=&quot;https://en.wikipedia.org/wiki/Cwm_%28window_manager%29&quot;&gt;&lt;code&gt;cwm&lt;/code&gt;&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;After a lot of digging, I found that PMan was a process viewing application built into Erlang, whose behavior was absorbed by Observer. PMan was written on the &lt;a href=&quot;https://www.erlang.org/docs/18/apps/gs/gs.pdf&quot;&gt;Graphics System&lt;/a&gt; (GS) application. GS was superseded by &lt;a href=&quot;https://www.erlang.org/doc/man/wx.html&quot;&gt;&lt;code&gt;wx&lt;/code&gt;&lt;/a&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn14&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn14&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;wx&lt;/code&gt; is an Erlang port of &lt;a href=&quot;https://www.wxwidgets.org/&quot;&gt;wxWidgets&lt;/a&gt; a cross-platform GUI library.&lt;/span&gt;&lt;/span&gt; for graphical applications for Erlang.&lt;/p&gt;
&lt;p&gt;PMan and the GS related backends were removed in &lt;a href=&quot;https://www.erlang.org/patches/otp-17.0&quot;&gt;OTP 17.0&lt;/a&gt;. If I checkout a version of OTP prior to OTP 17, I can finally find what &lt;code&gt;pman_process&lt;/code&gt; is doing. Prior to its removal, it was located in &lt;code&gt;lib/pman/src/pman_process.erl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The module includes a purpose comment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A front-end to the &lt;code&gt;erlang:process_info()&lt;/code&gt; functions, that
can handle processes on different nodes in a transparent
way.&lt;/p&gt;
&lt;p&gt;Also some convenience functions for process info, as well
as some application specific functions for process 
classification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This purpose explains why it might contain an &lt;code&gt;is_system_process/1&lt;/code&gt; function.&lt;/p&gt;
&lt;section id=&quot;One-Last-Mystery&quot;&gt;
&lt;h3&gt;One Last Mystery&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pman_process&lt;/code&gt; contains a few &lt;code&gt;-define&lt;/code&gt; calls that declare module constants that are lists of process names and function signatures that mark something as a &amp;ldquo;system&amp;rdquo; process.&lt;/p&gt;
&lt;p&gt;Where does this list come from? Why is hard coded? How do you determine what needs to be on these lists?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git blame&lt;/code&gt; gives me no answers, the code for &lt;code&gt;pman_process&lt;/code&gt; was added to the OTP git repo in its initial commit in 2009. And it remained untouched until it was removed prior to OTP 17.0.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/erlang-process-shell</id>
<link href="https://erikarow.land/notes/erlang-process-shell" />
<title>When is an Erlang process a shell?</title>
<updated>2023-10-31T00:00:00+00:00</updated>
<dc:date>2023-10-31T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Git-Spelunking-with-Bisect&quot;&gt;
&lt;h1&gt;Git Spelunking with Bisect&lt;/h1&gt;
&lt;p&gt;Today, I continued on the git spelunking that prompted the post from &lt;a href=&quot;/notes/git-checkout-tag&quot;&gt;yesterday&lt;/a&gt;. I&amp;rsquo;ve been diving deeper in the Erlang codebase today, and so I needed some new tools.&lt;/p&gt;
&lt;section id=&quot;git-bisect&quot;&gt;
&lt;h2&gt;&lt;code&gt;git bisect&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git-bisect&lt;/code&gt; lets you search for a commit using binary search. I wanted to find the last commit that contained a particular Erlang function in the &lt;a href=&quot;https://github.com/erlang/otp&quot;&gt;&lt;code&gt;otp&lt;/code&gt;&lt;/a&gt; codebase. My process looked something like this:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thank you to Yannick for helping me learn how to use this.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You can read more about &lt;code&gt;git-bisect&lt;/code&gt; &lt;a href=&quot;https://git-scm.com/docs/git-bisect&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;First I start the bisect&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git bisect start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I specify a commit that didn&amp;rsquo;t have the function, in this case HEAD:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git bisect bad
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I specify a commit that &lt;strong&gt;does&lt;/strong&gt; have the function. In this case I knew that the function was in OTP_R14A. &lt;code&gt;git-bisect&lt;/code&gt; lets me specify a tag here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git bisect good OTP_R14A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point &lt;code&gt;git-bisect&lt;/code&gt; took me automatically to a commit that was roughly halfway between those two commits. While I&amp;rsquo;m here, I can run whatever checks I want to on the command line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rg &#x27;&amp;lt;function-to-find&amp;gt;&#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the function is there, I mark &lt;code&gt;git bisect good&lt;/code&gt;. If it&amp;rsquo;s not, then I mark &lt;code&gt;git bisect bad&lt;/code&gt;. Either way, &lt;code&gt;git-bisect&lt;/code&gt; moves me to the next pivot commit in the search. &lt;code&gt;otp&lt;/code&gt; has tens of thousands of commits, but binary search meant that it took around 15 steps to get the commit I wanted.&lt;/p&gt;
&lt;p&gt;Once I was done, I could run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git bisect reset
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get back to where I started.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s great to know that I can run whatever arbitrary manual commands I need at each manual step, but in this case I was running the same command each time.&lt;/p&gt;
&lt;p&gt;In this case, that&amp;rsquo;s where &lt;code&gt;git bisect run&lt;/code&gt; comes in:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;git-bisect-run&quot;&gt;
&lt;h2&gt;&lt;code&gt;git bisect run&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git bisect run&lt;/code&gt; lets you run a script to check for &lt;code&gt;good/bad&lt;/code&gt; at each step of the binary search, instead of having to do it manually.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thank you to &lt;a href=&quot;http://mikkel.ca/&quot;&gt;Mikkel&lt;/a&gt; for suggesting this to me.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You can read more about &lt;code&gt;git-bisect run&lt;/code&gt; &lt;a href=&quot;https://git-scm.com/docs/git-bisect#_bisect_run&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The initial suggestion I got was to use &lt;code&gt;git grep&lt;/code&gt; as in:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git bisect start
git bisect bad
git bisect good &quot;[tag]&quot;
git bisect run git grep &quot;[function name]&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But I knew that there were &lt;strong&gt;two&lt;/strong&gt; versions of &lt;code&gt;is_system_process/1&lt;/code&gt; at various times in the Erlang codebase. I only wanted to know about the older one,
so I used this modified version instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git bisect start
git bisect bad
git bisect good OTP_R14A
git bisect run git grep &quot;[function name]&quot; &quot;path/to/folder/*&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;path/to/folder/*&lt;/code&gt; was pointing the folder I knew the function was in.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I initially tried to use the exact filename, but in failing commits the file didn&amp;rsquo;t exist throwing an error that &lt;code&gt;git bisect run&lt;/code&gt; didn&amp;rsquo;t know how to deal with. The glob seemed to avoid this problem.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;With this, the binary search took a few seconds and quickly returned the same commit that I found manually.&lt;/p&gt;
&lt;p&gt;Now that I had the commit in hand, I wanted to know what the &lt;em&gt;next&lt;/em&gt; tagged release that contained that commit was. Enter &lt;code&gt;git-describe&lt;/code&gt;:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;git-describe&quot;&gt;
&lt;h2&gt;&lt;code&gt;git describe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git-describe&lt;/code&gt; is purpose built for finding tags from commits. By default, it finds the tag that immediately predates the commit. But if you use the &lt;code&gt;--contains&lt;/code&gt; option, it will find the tag that &amp;ldquo;contains&amp;rdquo; the commit, that is the commit I want to find.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Credit to &lt;a href=&quot;https://unix.stackexchange.com/questions/47659/how-to-find-the-first-tag-that-contains-a-git-commit&quot;&gt;Stack Overflow&lt;/a&gt; for helping me find this one.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If the tag is exactly the commit, then it will only return the tag. Otherwise, it will have a suffix that shows:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://git-scm.com/docs/git-describe&quot;&gt;Source&lt;/a&gt; where you can read more about &lt;code&gt;git-describe&lt;/code&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I can use &lt;code&gt;sed&lt;/code&gt; to strip out the suffix, since I only want the tag name:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git describe --contains &quot;&amp;lt;commit&amp;gt;&quot; | sed &#x27;s/~.*//&#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another way to accomplish this is with &lt;code&gt;git tag --contains&lt;/code&gt;:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Miccah for this suggestion.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;code&gt;git-tag&lt;/code&gt; &lt;a href=&quot;https://git-scm.com/docs/git-tag&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git tag --contains &quot;&amp;lt;commit&amp;gt;&quot; --sort=creatordate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will return &lt;em&gt;all&lt;/em&gt; of the tags that contain the commit, sorted by their creation date.&lt;/p&gt;
&lt;p&gt;Now I have the tag I want, but when was it created? I found a couple techniques that work:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Technique-1-git-log--1&quot;&gt;
&lt;h2&gt;Technique 1: &lt;code&gt;git log -1&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git log&lt;/code&gt; will display information about the parents of a given commit. But if you use the &lt;code&gt;-1&lt;/code&gt; option, it will limit it to &lt;code&gt;1&lt;/code&gt; commit, only the one we pass to it. And we can pass a tag to it:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Credit to &lt;a href=&quot;https://stackoverflow.com/questions/13208734/get-the-time-and-date-of-git-tags&quot;&gt;Stack Overflow&lt;/a&gt; for this one too.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;code&gt;git-log&lt;/code&gt; &lt;a href=&quot;https://git-scm.com/docs/git-log&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git log -1 &quot;&amp;lt;tag&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will show the default information about the commit behind the tag.&lt;/p&gt;
&lt;p&gt;If I only wanted the date, I could use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git log -1 --format=%ai &quot;&amp;lt;tag&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Technique-2-git-for-each-ref&quot;&gt;
&lt;h2&gt;Technique 2: &lt;code&gt;git for-each-ref&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git for-each-ref&lt;/code&gt; will iterate over all refs that match a given pattern. It also lets you format information from that ref.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn12&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn12&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I found information on this one from two Stack Overflow answers: &lt;a href=&quot;https://stackoverflow.com/questions/6269927/how-can-i-list-all-tags-in-my-git-repository-by-the-date-they-were-created&quot;&gt;one&lt;/a&gt; and &lt;a href=&quot;https://stackoverflow.com/questions/13208734/get-the-time-and-date-of-git-tags&quot;&gt;two&lt;/a&gt;. The latter from a comment on the accepted answer.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn13&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn13&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;code&gt;git for-each-ref&lt;/code&gt; &lt;a href=&quot;https://git-scm.com/docs/git-for-each-ref&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;That pattern can be as specific as a single tag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git for-each-ref \
  --format=&quot;%(refname:short) | %(creatordate)&quot; \
  &quot;refs/tags/OTP_17.0-rc1&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like this one because I can easy generalize a solution to ask other questions. When was every tag released?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git for-each-ref \
  --format=&quot;%(refname:short) | %(creatordate)&quot; \
  &quot;refs/tags&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, it seems to sort alphabetically by &lt;code&gt;refname&lt;/code&gt;. If I want them in chronological order, I can add &lt;code&gt;--sort=creatordate&lt;/code&gt; on the end.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;I came out of this expedition with a rich collection of tools that I can use in future spelunking. All of these tools are built into &lt;code&gt;git&lt;/code&gt; and have excellent documentation in the &lt;a href=&quot;https://git-scm.com/docs&quot;&gt;reference manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I often read source code in order to get a better understanding of the tools, libraries, and software that I use. These &lt;code&gt;git&lt;/code&gt; tools allow me to explore that source code in specific historical context, and understand how codebases evolve and change over time.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Bonus-A-Simpler-Search-Method&quot;&gt;
&lt;h2&gt;Bonus: A Simpler Search Method&lt;/h2&gt;
&lt;p&gt;When I asked about how to find the commit I needed in a Recursers chat, I got more answers after I had already found the commit I was looking for. Here is one that was simpler than &lt;code&gt;git-bisect&lt;/code&gt;:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn14&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn14&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Nathan and Benjamin for this suggestion.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;git-log--S&quot;&gt;
&lt;h3&gt;&lt;code&gt;git log -S&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You can use &lt;code&gt;git log -S &quot;&amp;lt;name of function&amp;gt;&quot;&lt;/code&gt; to find commits that touch the string &lt;code&gt;&amp;lt;name of function&amp;gt;&lt;/code&gt;. I found this didn&amp;rsquo;t take much longer than &lt;code&gt;git bisect run&lt;/code&gt; on the Erlang codebase. And, I didn&amp;rsquo;t have to find an early &amp;ldquo;good&amp;rdquo; commit before searching.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/git-spelunking-bisect</id>
<link href="https://erikarow.land/notes/git-spelunking-bisect" />
<title>Git Spelunking with Bisect</title>
<updated>2023-10-29T00:00:00+00:00</updated>
<dc:date>2023-10-29T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Git-Checkout-Tag&quot;&gt;
&lt;h1&gt;Git Checkout Tag&lt;/h1&gt;
&lt;p&gt;You can checkout a tag in a git repo by using&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is pretty useful for exploring historical version of code bases. &amp;ldquo;What was this codebase like at release X?&amp;rdquo; I needed this in order to find a removed function in Erlang.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git checkout &amp;lt;tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple as that.&lt;/p&gt;
&lt;p&gt;Note that running this command without a branch will put you in &amp;ldquo;detached HEAD&amp;rdquo; state, meaning that any commits you make will be reachable only by their exact hash. If you want to make changes with a tag as your starting point, use &lt;code&gt;-b &amp;lt;branch name&amp;gt;&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git checkout -b &amp;lt;branch name&amp;gt; &amp;lt;tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read more in the &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Basics-Tagging#_checking_out_tags&quot;&gt;git documentation&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Pathspecs&quot;&gt;
&lt;h2&gt;Pathspecs&lt;/h2&gt;
&lt;p&gt;When I initially looked up how to do this,
I found instructions to use &lt;code&gt;git checkout tags/&amp;lt;tag&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is contrary to git&amp;rsquo;s own documentation,
but it worked!&lt;/p&gt;
&lt;p&gt;This seems to work because tags are a ref in the &lt;a href=&quot;https://git-scm.com/docs/gitglossary#tag&quot;&gt;&lt;code&gt;refs/tags&lt;/code&gt; namespace&lt;/a&gt;,
and git correctly identifies the right tag, and thus the right commit from there.
I believe this is the same mechanism as when you give a short hash and git finds the correct commit.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/git-checkout-tag</id>
<link href="https://erikarow.land/notes/git-checkout-tag" />
<title>Git Checkout Tag</title>
<updated>2023-10-27T00:00:00+00:00</updated>
<dc:date>2023-10-27T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Firefox-Has-a-Built-In-Screenshot-Tool&quot;&gt;
&lt;h1&gt;Firefox Has a Built-In Screenshot Tool&lt;/h1&gt;
&lt;p&gt;Today I learned that Firefox has a built-in screenshot tool. It&amp;rsquo;s bound to &lt;code&gt;ctrl+shift+S&lt;/code&gt; and allows you to easily select an element of the screen or a selection of the screen. Firefox then gives you the option to copy that selection to clipboard or save it as an image.&lt;/p&gt;
&lt;p&gt;Example&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Here I took a screenshot multiple times to get the recursive effect.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Firefox Screenshot Example image of the darkmode version of this blog post with recursive versions used in the screenshot itself&quot; src=&quot;/firefox-screenshot-example.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;Firefox documents this shortcut in its section on &lt;a href=&quot;https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly#w_tools&quot;&gt;tools&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/firefox-screenshot-tool</id>
<link href="https://erikarow.land/notes/firefox-screenshot-tool" />
<title>Firefox Has a Built-In Screenshot Tool</title>
<updated>2023-10-25T00:00:00+00:00</updated>
<dc:date>2023-10-25T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Paper-Four-Concepts-for-Resilience-Engineering&quot;&gt;
&lt;h1&gt;Paper: Four Concepts for Resilience Engineering&lt;/h1&gt;
&lt;p&gt;Today&amp;rsquo;s paper is by David Woods: &lt;a href=&quot;https://www.researchgate.net/publication/276139783_Four_concepts_for_resilience_and_the_implications_for_the_future_of_resilience_engineering&quot;&gt;Four concepts for resilience and the implications for the future of resilience engineering&lt;/a&gt;. I found this paper through &lt;a href=&quot;https://ferd.ca/notes/paper-four-concepts-for-resilience-engineering.html&quot;&gt;Fred Hebert&amp;rsquo;s excellent summary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Resilience has been used a number of different ways in Resilience Engineering literature. This conflation of different definitions makes it difficult to parse and understand what that literature is arguing for and why.&lt;/p&gt;
&lt;p&gt;Woods&amp;rsquo; paper attempts to codify these various definitions into four categories. The categories clarify which properties of a system we&amp;rsquo;re talking about, and which aspects of a system are worth studying.&lt;/p&gt;
&lt;section id=&quot;Resilience-as-Rebound&quot;&gt;
&lt;h2&gt;Resilience as Rebound&lt;/h2&gt;
&lt;p&gt;Rebound is about returning to normal functioning after a disruption.&lt;/p&gt;
&lt;p&gt;This ability to rebound seems to depend directly on the conditions before the disrupting event. How was the system prepared before the chaos began?&lt;/p&gt;
&lt;p&gt;While literature on rebound tends to focus on individual disruptions or traumas, the more interesting thing to study is the idea of surprises. A surprise is, to quote Woods:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the event is a surprise when it falls outside the
scope of variations and disturbances that the system in question is
capable of handling&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A surprise is an event that challenges an existing model and forces the system to learn or adapt the model.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Resilience-as-Robustness&quot;&gt;
&lt;h2&gt;Resilience as Robustness&lt;/h2&gt;
&lt;p&gt;Robustness is the ability of a system to resist disruptions. However, robustness is specifically defined as resistance against a known set of disruptions. From Rebound, we know that a system will often deal with surprises, that by definition, fall outside the robustness a model.&lt;/p&gt;
&lt;p&gt;Thus resilience is more interested in adapting to surprise than preparing against known threats. However, this distinction is lost when conflating resilience with robustness.&lt;/p&gt;
&lt;p&gt;Another problem is that expanding robustness in one way, often opens additional vectors of failure in the event of surprises. For example, an umbrella gives you some shelter from rain, but the mechanism can jam or strong winds can drag you into unwanted positions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Resilience-as-Graceful-Extensibility&quot;&gt;
&lt;h2&gt;Resilience as Graceful Extensibility&lt;/h2&gt;
&lt;p&gt;Graceful Extensibility sees resilience as the opposite of brittleness. Where brittleness is how a system performs when it&amp;rsquo;s pushed to near or beyond its limits.&lt;/p&gt;
&lt;p&gt;This is a definition of resilience that specifically cares about the kinds of surprise that I talked about in Rebound. While surprise falls outside of our systems limits, it has regular characteristics because many classes of challenge re-occur.&lt;/p&gt;
&lt;p&gt;Graceful extensibility is play with the idea of graceful degradation. Graceful extensibility suggests the ability to grow from surprises which stands in contrast to robustness or graceful degradation, which only allow us to mitigate breakdowns.&lt;/p&gt;
&lt;p&gt;Another aspect of concern is &lt;em&gt;decompensation&lt;/em&gt; where exhaustion of a system under sustained disruption reduces the capacity of the system to adapt to new disruptions. Think on-call fatigue in an operations teams or deformation of a material under stress that changes its properties.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;An effective way to &amp;ldquo;cut&amp;rdquo; paper without scissors is to fold it back and forth across a joint until the paper gives way with little force. Allowing you to tear the paper straight by hand.&lt;/span&gt;&lt;/span&gt; As Woods writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When the time to recovery increases and/or the level recovered to
decreases, this pattern indicates that a system is exhausting its
ability to handle growing or repeated challenges, in other words,
the system is nearing saturation of its range of adaptive behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/section&gt;
&lt;section id=&quot;Resilience-as-Sustained-Adaptability&quot;&gt;
&lt;h2&gt;Resilience as Sustained Adaptability&lt;/h2&gt;
&lt;p&gt;Sustained adaptability asks three questions of a resilience engineer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
What governance or architectural characteristics explain
the difference between systems that have sustained adapt-
ability that don&amp;rsquo;t?
&lt;/li&gt;
&lt;li&gt;
What design principles and techniques allow you to engineer sustained adaptability?
&lt;/li&gt;
&lt;li&gt;
How would you know if you succeeded in engineering sustained adaptability in a system?
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Predictable challenges that test a system include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Surprises will continue to challenge boundaries of a system.
&lt;/li&gt;
&lt;li&gt;
Conditions will change over time, shifting the boundaries of a system.
&lt;/li&gt;
&lt;li&gt;
When, not if, the system fails to adapt, people will need to bear that burden.
&lt;/li&gt;
&lt;li&gt;
How the system needs to gracefully extend, and what allows you to gracefully extend will change over time.
&lt;/li&gt;
&lt;li&gt;
The system will need to be able to benefit from surprises, as discussed in graceful extensibility.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Architecting a system to have sustained adaptability relies on understanding that all adaptive systems are constrained by trade-offs, and that certain architectures allow for adjustment of those trade-offs.&lt;/p&gt;
&lt;p&gt;Woods argues that definitions 1 and 2 have led to fewer developments and are less useful overall than definitions 3 and 4. Though he exercises caution in his judgment given the youth of the field.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Jeff for reading and editing with me for these notes.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/paper-four-concepts-resilience</id>
<link href="https://erikarow.land/notes/paper-four-concepts-resilience" />
<title>Paper: Four Concepts for Resilience Engineering</title>
<updated>2023-10-06T00:00:00+00:00</updated>
<dc:date>2023-10-06T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Configure-IEx-to-Show-Lists-as-Lists&quot;&gt;
&lt;h1&gt;Configure IEx to Show Lists as Lists&lt;/h1&gt;
&lt;p&gt;Charlists are a holdover from Erlang as an alternate form of string. In Erlang, strings are syntax sugar on a list of binary characters that make up that string. In Elixir, strings are syntax sugar over UTF-8 encoded binaries.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Erlang also has the &lt;a href=&quot;https://www.erlang.org/doc/programming_examples/bit_syntax.html&quot;&gt;concept of binaries&lt;/a&gt; (called a bitstring), they just aren&amp;rsquo;t the default string implementation. Elixir chose to implement strings directly on top of bitstrings instead of lists.&lt;/span&gt;&lt;/span&gt; Since Elixir has first class support for Erlang code, it needs to easy to convert Elixir strings into the charlists that Erlang functions expect.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you&amp;rsquo;re interested in reading more, &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/List.html#module-charlists&quot;&gt;here&lt;/a&gt; is a note about charlists in Elixir&amp;rsquo;s documentation.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Elixir&amp;rsquo;s support for charlists manifests in interesting ways. By default, Elixir&amp;rsquo;s IEx renders lists that contain printable characters as charlists.&lt;/p&gt;
&lt;p&gt;Thus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex()&amp;gt; Enum.chunk_every(1..10, 2)
[[1, 2], [3, 4], [5, 6], &#x27;\a\b&#x27;, &#x27;\t\n&#x27;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The single-quoted &lt;code&gt;&#x27;&lt;/code&gt; characters on the right are charlists. However, it&amp;rsquo;s a bit annoying to have to translate between charlists and the actual lists. In this case: &lt;code&gt;[7, 8]&lt;/code&gt; and &lt;code&gt;[9, 10]&lt;/code&gt; that those charlists represent.&lt;/p&gt;
&lt;p&gt;The pretty printing that IEx does when it returns a value is powered by Elixir&amp;rsquo;s &lt;code&gt;inspect&lt;/code&gt;. &lt;code&gt;inspect&lt;/code&gt; takes some configuration, as detailed in &lt;code&gt;Inspect.Opts&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read the rest of the options available &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Inspect.Opts.html&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;:infer&lt;/code&gt; is why our example above is &lt;em&gt;partially&lt;/em&gt; charlists, it only recognises the list starting with &lt;code&gt;7&lt;/code&gt; to be entirely printable characters and opportunistically transforms it.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;:charlists&lt;/code&gt; - when &lt;code&gt;:as_charlists&lt;/code&gt; all lists will be printed as charlists,
non-printable elements will be escaped.
When &lt;code&gt;:as_lists&lt;/code&gt; all lists will be printed as lists.&lt;/p&gt;
&lt;p&gt;When the default &lt;code&gt;:infer&lt;/code&gt;, the list will be printed as a charlist if it is
printable, otherwise as list. See &lt;code&gt;List.ascii_printable?/1&lt;/code&gt; to learn when a
charlist is printable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;Kernel.inspect/2&lt;/code&gt; accepts a list of options that are internally translated to an &lt;code&gt;Inspect.Opts&lt;/code&gt; struct:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex()&amp;gt; inspect(Enum.chunk_every(1..10, 2), charlists: :as_lists)
&quot;[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I have a string that looks correct, but I would like IEx to return the value, but print it correctly. And I would like to not have to invoke &lt;code&gt;inspect&lt;/code&gt; with my settings every time.&lt;/p&gt;
&lt;p&gt;Thankfully, IEx gives us &lt;code&gt;IEx.configure&lt;/code&gt; that allow me to configure my IEx session. &lt;code&gt;IEx.configure&lt;/code&gt; takes a keyword list of options to set, and offers &lt;code&gt;inspect&lt;/code&gt; as a possible key:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex()&amp;gt; IEx.configure(inspect: [charlists: :as_lists])
:ok
iex()&amp;gt; Enum.chunk_every(1..10, 2)
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;p&gt;If I want to make this happen every time, I can add the &lt;code&gt;IEx.configure&lt;/code&gt; call to &lt;code&gt;~/.iex.exs&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You can set things on a per-project basis too, read more &lt;a href=&quot;https://hexdocs.pm/iex/1.12/IEx.html#module-the-iex-exs-file&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/iex-charlists</id>
<link href="https://erikarow.land/notes/iex-charlists" />
<title>Configure IEx to Show Lists as Lists</title>
<updated>2023-10-02T00:00:00+00:00</updated>
<dc:date>2023-10-02T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Just-Add-Water&quot;&gt;
&lt;h1&gt;Just Add Water&lt;/h1&gt;
&lt;p&gt;Or, Using Partial Application In Elixir for Better Errors.&lt;/p&gt;
&lt;p&gt;Today, I was adapting the generator for a &lt;a href=&quot;https://grimgrains.com/site/about.html&quot;&gt;recipe website&lt;/a&gt; written by Hundred Rabbits into Elixir. While adapting their idiomatic C code into Elixir, I needed a way to pass a predefined list of ingredients to the builder API for Recipes.&lt;/p&gt;
&lt;p&gt;To do this, I defined a function that returned a keyword list&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;code&gt;cheese: cheese&lt;/code&gt; syntax looks a bit funny, but it&amp;rsquo;s Elixir syntax sugar for &lt;code&gt;{:cheese, cheese}&lt;/code&gt; where the second &lt;code&gt;cheese&lt;/code&gt; is the bound variable.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def ingredients do
  cheese = create_ingredient(...)

  salt = create_ingredient(...)

  [cheese: cheese, salt: salt]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then in my builder API, I called that function inside the builder scope:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def recipes do
  ingredients = Ingredients.ingredients()

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to add an ingredient to a recipe, I used a function &lt;code&gt;add_ingredient_quantity/3&lt;/code&gt;, used something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def recipes do 
  ingredients = Ingredients.ingredients()

  create_recipe(&quot;salted cheese&quot;)
  |&amp;gt; add_ingredient_quantity(ingredient[:cheese], &quot;2 oz&quot;)
  |&amp;gt; add_ingredient_quantity(ingredient[:salt], &quot;1 teaspoon&quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This worked great for ingredients that I had already defined in my keyword list, but the &lt;code&gt;Access&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;code&gt;Access&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Access.html&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt; behaviour that powers Elixir&amp;rsquo;s &lt;code&gt;[]&lt;/code&gt; syntax returns &lt;code&gt;nil&lt;/code&gt; if a key isn&amp;rsquo;t found in the accessed object.&lt;/p&gt;
&lt;p&gt;I wanted a way to detect that I needed to define a new ingredient in a recipe, so that every ingredient gets its own page, like Grim Grains. My naive solution was to put a guard clause on &lt;code&gt;add_ingredient_quantity&lt;/code&gt; that checked if the ingredient was nil:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def add_ingredient_quantity(recipe, ingredient, quantity) when not is_nil(ingredient) do
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would certainly complain, because of a pattern match error. However, the &lt;code&gt;Access&lt;/code&gt; had already returned a &lt;code&gt;nil&lt;/code&gt;, so the missing ingredient&amp;rsquo;s atom wasn&amp;rsquo;t available for an error message.&lt;/p&gt;
&lt;p&gt;This became evident when I tried to add water&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;You would want to drink some water if you were eating that much salted cheese, after all.&lt;/span&gt;&lt;/span&gt; to my recipe:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def recipes do 
  ingredients = Ingredients.ingredients()

  create_recipe(&quot;salted cheese&quot;)
  |&amp;gt; add_ingredient_quantity(ingredient[:cheese], &quot;2 oz&quot;)
  |&amp;gt; add_ingredient_quantity(ingredient[:salt], &quot;1 teaspoon&quot;)
  |&amp;gt; add_ingredient_quantity(ingredient[:water], &quot;1 quart&quot;) 
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This resulted in a pattern match error, but the error only knew that it was passed a &lt;code&gt;nil&lt;/code&gt; with no context about where that &lt;code&gt;nil&lt;/code&gt; came from.&lt;/p&gt;
&lt;section id=&quot;Partial-Application-in-Elixir&quot;&gt;
&lt;h2&gt;Partial Application in Elixir&lt;/h2&gt;
&lt;p&gt;To solve this, I replaced the &lt;code&gt;ingredient[:water]&lt;/code&gt; call&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I first thought about overriding the &lt;code&gt;Access&lt;/code&gt; behaviour to return something other than &lt;code&gt;nil&lt;/code&gt;, but I decided against it.&lt;/span&gt;&lt;/span&gt; with a partial application.&lt;/p&gt;
&lt;p&gt;In Elixir I can use an anonymous function to partially apply a named Elixir function. Here, I wanted to get a value out of a specific Keyword List, so I chose &lt;code&gt;Keyword.fetch&lt;/code&gt;. &lt;code&gt;Keyword.fetch&lt;/code&gt; takes two arguments: a keyword list and a key to get&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about &lt;code&gt;Keyword.fetch/2&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Keyword.html#fetch/2&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;. By partially applying &lt;code&gt;Keyword.fetch&lt;/code&gt; with &lt;code&gt;ingredients&lt;/code&gt; and wrapping it in a &lt;code&gt;with&lt;/code&gt; statement I can raise a helpful error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def recipes do
  ingredients = Ingredients.ingredients()
  get_ingredient = fn key -&amp;gt; 
    with {:ok, value} &amp;lt;- Keyword.fetch(ingredients, key) do
      value
    else
      :error -&amp;gt; raise &quot;#{key} not found in ingredients&quot;
    end
  end

  create_recipe(&quot;salted cheese&quot;)
  |&amp;gt; add_ingredient_quantity(get_ingredient.(:cheese), &quot;2 oz&quot;)
  |&amp;gt; add_ingredient_quantity(get_ingredient.(:salt), &quot;1 teaspoon&quot;)
  |&amp;gt; add_ingredient_quantity(get_ingredient.(:water), &quot;1 quart&quot;) 
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we&amp;rsquo;re using an anonymous function, so &lt;code&gt;get_ingredient&lt;/code&gt; needs to be applied with the &lt;code&gt;.&lt;/code&gt; operator&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I initially tried to use the capture operator on &lt;code&gt;Keyword.get/3&lt;/code&gt;, passing &lt;code&gt;raise&lt;/code&gt; as the default as shown &lt;a href=&quot;https://paste.sr.ht/~erikareads/ba76dc7b0e0d5b9e66363f6d999c215fadcd80b5&quot;&gt;here&lt;/a&gt;. This successfully raised a helpful error on a missing key, but it eagerly raised on every key!&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now, when I&amp;rsquo;m missing an ingredient I&amp;rsquo;ll get a helpful error message that reminds me to just add it.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/just-add-water</id>
<link href="https://erikarow.land/notes/just-add-water" />
<title>Just Add Water</title>
<updated>2023-10-02T00:00:00+00:00</updated>
<dc:date>2023-09-25T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Parsing-TSVs-in-Go&quot;&gt;
&lt;h1&gt;Parsing TSVs in Go&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m building a terminal application to learn Go,
and I wanted to persist data using Tab Separated Values.
Here are some of the things I learned while figuring out how to do that.&lt;/p&gt;
&lt;section id=&quot;CSV-Reader-in-Standard-Library&quot;&gt;
&lt;h2&gt;CSV Reader in Standard Library&lt;/h2&gt;
&lt;p&gt;Go has a CSV reader in their standard library.
You can import it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;import (
	&quot;encoding/csv&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once it&amp;rsquo;s imported, you can create a CSV &lt;code&gt;Reader&lt;/code&gt; by calling &lt;code&gt;csv.NewReader&lt;/code&gt; on an &lt;code&gt;io.Reader&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I learned about reading CSVs in Go from &lt;a href=&quot;https://gosamples.dev/read-csv/&quot;&gt;Go Samples&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;file, err := os.Open(&quot;my.tsv&quot;)
if err != nil {
	log.Fatal(err)
}

// remember to close the file at the end of the program
defer file.Close()

csvReader := csv.NewReader(file)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since I want to read Tab-Separated Values instead of Comma-Separated Values,
I can set the &lt;code&gt;Comma&lt;/code&gt; used by my CSV Reader to be a tab character:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;csvReader.Comma = &#x27;\t&#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don&amp;rsquo;t expect my CSV to be memory intensive, 
so I can read it all into memory with &lt;code&gt;csvReader.ReadAll()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;data, err := csvReader.ReadAll()
if err != nil {
	log.Fatal(err)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Higher-Order-Functions-in-Go-Kinda&quot;&gt;
&lt;h2&gt;Higher Order Functions in Go&amp;hellip; Kinda&lt;/h2&gt;
&lt;p&gt;Now I have TSV loaded in memory,
but &lt;code&gt;csvReader.ReadAll()&lt;/code&gt; returns a slice of records of type &lt;code&gt;[]string&lt;/code&gt;.
If I want to convert these record into structs,
I&amp;rsquo;ll need to parse the records myself.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m used to working with functional languages,
where I would take the list of records 
and use &lt;code&gt;map&lt;/code&gt; to transform them into structs.&lt;/p&gt;
&lt;section id=&quot;Generics&quot;&gt;
&lt;h3&gt;Generics&lt;/h3&gt;
&lt;p&gt;Go doesn&amp;rsquo;t have a builtin &lt;code&gt;map&lt;/code&gt; function,
but we can build one using generics:&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I learned how to build a generic map function from &lt;a href=&quot;https://zetcode.com/golang/filter-map/&quot;&gt;ZetCode&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Note we have to call the function &lt;code&gt;map2&lt;/code&gt; because &lt;code&gt;map&lt;/code&gt; is reserved for the hashmap in Go.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func map2[InputType, OutputType any](
	data []InputType, f func(InputType) OutputType) []OutputType {

	result := make([]OutputType, 0, len(data))

	for _, element := range data {
		result = append(result, f(element))
	}

	return result
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function takes a slice of &lt;code&gt;InputType&lt;/code&gt; 
and a function that takes &lt;code&gt;InputType&lt;/code&gt; and returns &lt;code&gt;any&lt;/code&gt; &lt;code&gt;OutputType&lt;/code&gt;,
iterates over the slice building a return slice by calling the function on each element before appending.&lt;/p&gt;
&lt;p&gt;Because Go supports Generics, we can vaguely specify that the input must be of &lt;strong&gt;a&lt;/strong&gt; type,
but not worry about which type that is until we see the input data.
Same goes for the output type, 
it&amp;rsquo;s entirely determined by the specific function that&amp;rsquo;s passed in as the second argument.&lt;/p&gt;
&lt;p&gt;Prior to learning about this version of &lt;code&gt;map2&lt;/code&gt;,
I didn&amp;rsquo;t know that Go &lt;strong&gt;had&lt;/strong&gt; an &lt;code&gt;any&lt;/code&gt; type.
It&amp;rsquo;s perfect for a situation like this,
where we don&amp;rsquo;t care what type the function returns, as long as it&amp;rsquo;s consistent.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Slices&quot;&gt;
&lt;h3&gt;Slices&lt;/h3&gt;
&lt;p&gt;One thing that was new to me coming to go is how Go handles &lt;code&gt;slices&lt;/code&gt;.
Elixir uses immutable lists, but Go seems to use allocated arrays called slices.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Question: Why are they called slices? Does Go have something called arrays?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://pkg.go.dev/builtin#make&quot;&gt;&lt;code&gt;make&lt;/code&gt;&lt;/a&gt; function from before takes a type, a starting size, and a capacity,
and allocates and returns an initialized object of that type.
In the case of &lt;code&gt;map2&lt;/code&gt;, that object is a slice of type &lt;code&gt;OutputType&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then we call &lt;a href=&quot;https://pkg.go.dev/builtin#append&quot;&gt;&lt;code&gt;append&lt;/code&gt;&lt;/a&gt;, 
which will take an allocated slice of a type,
and items of that type, and append those items to the end of the slice.&lt;/p&gt;
&lt;p&gt;If that slice still has sufficient capacity to accommodate the new items,
it will reslice to include the new items.
Otherwise, a new array will be allocated.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The documentation for &lt;code&gt;append&lt;/code&gt; refers to arrays, which implies that arrays are distinct from slices. Based on the way this function is written, I would guess that arrays refer to the physical memory that has been allocated, and that slices are a reference to that allocated array, which may not be the whole array. I&amp;rsquo;ll need to do further reading to confirm.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Parsing-at-last&quot;&gt;
&lt;h2&gt;Parsing at last&lt;/h2&gt;
&lt;p&gt;Now that we have our &lt;code&gt;map2&lt;/code&gt; function we can invoke it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;result := map2(data, func(s []string) Bookmark {
	return Bookmark{Name: s[0], LastRead: s[1], Chapter: s[2]}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we define an anonymous function that takes a record of type &lt;code&gt;[]string&lt;/code&gt;,
and returns a struct of type &lt;code&gt;Bookmark&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; here will be a slice of type &lt;code&gt;Bookmark&lt;/code&gt;,
with each &lt;code&gt;Bookmark&lt;/code&gt; containing the data from the relevant row from the TSV.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/parsing-tsvs-in-go</id>
<link href="https://erikarow.land/notes/parsing-tsvs-in-go" />
<title>Parsing TSVs in Go</title>
<updated>2023-10-02T00:00:00+00:00</updated>
<dc:date>2023-06-17T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Customizing-Fonts-in-Various-Places&quot;&gt;
&lt;h1&gt;Customizing Fonts in Various Places&lt;/h1&gt;
&lt;p&gt;Notes on how I&amp;rsquo;ve customized fonts in various places.&lt;/p&gt;
&lt;p&gt;I like to use &lt;a href=&quot;https://brailleinstitute.org/freefont&quot;&gt;Atkinson Hyperlegible&lt;/a&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;/other/colophon&quot;&gt;You&amp;rsquo;re reading it now&lt;/a&gt;, unless you&amp;rsquo;ve overridden this websites fonts.&lt;/span&gt;&lt;/span&gt; where I can for the ability to distinguish characters.&lt;/p&gt;
&lt;section id=&quot;Firefox&quot;&gt;
&lt;h2&gt;Firefox&lt;/h2&gt;
&lt;p&gt;Firefox uses the system font by default.&lt;/p&gt;
&lt;p&gt;Adding the following to my NixOS &lt;code&gt;configuration.nix&lt;/code&gt; did the trick:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fonts.fontconfig.defaultFonts = {
  sansSerif = [
    &quot;Atkinson Hyperlegible&quot;
     # ...
  ];
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One quick &lt;code&gt;nixos-rebuild switch&lt;/code&gt; later, and the new font was in place.&lt;/p&gt;
&lt;p&gt;Note that I needed to restart Firefox in order for the font to take effect.&lt;/p&gt;
&lt;p&gt;This left my fontsize in my address bar too small, so I modified:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;layout.css.devPixelsPerPx = 1.25
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;about:config&lt;/code&gt; for Firefox&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Check out the instructions in &lt;a href=&quot;https://support.mozilla.org/en-US/questions/1239467&quot;&gt;this answer&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;. Note this resizes everything in Firefox, but overall the effect is worth it for me.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Mastodon&quot;&gt;
&lt;h2&gt;Mastodon&lt;/h2&gt;
&lt;p&gt;I use the standard Mastodon web client, which includes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Settings -&amp;gt; Appearance -&amp;gt; Animations and Accessibility -&amp;gt; &quot;Use system&#x27;s default font&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checking the box and hitting save loaded my font without issue.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Slack-browser&quot;&gt;
&lt;h2&gt;Slack (browser)&lt;/h2&gt;
&lt;p&gt;Updating the font in Slack is easy as&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I learned how to do this from this &lt;a href=&quot;https://www.theverge.com/21432669/slack-font-change-how-to&quot;&gt;verge article&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/slackfont Atkinson Hyperlegible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I ever want to reset the font I can use the slash command without an argument:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/slackfont
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Installing-fonts-on-NixOS&quot;&gt;
&lt;h2&gt;Installing fonts on NixOS&lt;/h2&gt;
&lt;p&gt;Setting the system font on NixOS was easy, but first I needed to install the font&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more in the &lt;a href=&quot;https://nixos.wiki/wiki/Fonts&quot;&gt;wiki&lt;/a&gt; for NixOS.&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;My fonts path for my user is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$HOME/.local/share/fonts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I copied the Atkinson Hyperlegible &lt;code&gt;.otf&lt;/code&gt; files there,
then ran:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fc-cache
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/custom-fonts</id>
<link href="https://erikarow.land/notes/custom-fonts" />
<title>Customizing Fonts in Various Places</title>
<updated>2023-10-02T00:00:00+00:00</updated>
<dc:date>2023-08-20T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;A-Joy-to-Work-With&quot;&gt;
&lt;h1&gt;A Joy to Work With&lt;/h1&gt;
&lt;p&gt;Today, I&amp;rsquo;ve been playing &lt;a href=&quot;https://en.wikipedia.org/wiki/Joy_(programming_language%29&quot;&gt;Joy&lt;/a&gt;, a purely functional concatenative programming language.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Shae for reminding me of Joy, and for suggesting that it might be useful for systems programming.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Everything in Joy is a function that takes a stack and returns a stack.&lt;/p&gt;
&lt;p&gt;Hello world looks like this&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Sourced from &lt;a href=&quot;https://en.wikibooks.org/wiki/Computer_Programming/Hello_world#Joy&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-joy&quot;&gt;&quot;Hello, world!\n&quot; putchars .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Piece by piece, &lt;code&gt;&quot;Hello, world!\n&quot;&lt;/code&gt; puts a literal string on the stack.
&lt;code&gt;putchars&lt;/code&gt; takes a stack consisting of a single string, and prints it to the console. The &lt;code&gt;.&lt;/code&gt; character tells joy to execute the sequence of functions.&lt;/p&gt;
&lt;section id=&quot;Command-Line-Arguments&quot;&gt;
&lt;h2&gt;Command Line Arguments&lt;/h2&gt;
&lt;p&gt;My interest in Joy is for short executable programs, so I wanted to know how to learn how to use command line arguments in Joy.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I came up with&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;m using a &lt;code&gt;joy&lt;/code&gt; executable compiled from &lt;a href=&quot;https://github.com/Wodan58/Joy&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-joy&quot;&gt;#!/usr/bin/env joy
argv 1 drop [&quot; &quot; concat] map [putchars] step .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Piece by piece:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;argv&lt;/code&gt; takes all arguments passed in with the program, including the program&amp;rsquo;s name, and returns an aggregate (here a list of strings).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1&lt;/code&gt; is a pure function that takes a stack and adds itself to that stack.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;drop&lt;/code&gt; takes an aggregate and a number, and drops &lt;code&gt;number&lt;/code&gt; of elements from the aggregate. In this case, the name of the calling program.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[&quot; &quot; concat]&lt;/code&gt; is a quote, which allows me to pass a function unexecuted onto the stack. I believe in this case the &lt;code&gt;concat&lt;/code&gt; is partially applied with &lt;code&gt;&quot; &quot;&lt;/code&gt; as the second argument.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;concat&lt;/code&gt; takes two sequences and concatenates them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt; takes an aggregate and a quoted function, and executes the function on each element of the aggregate, returning a stack containing a new aggregate with elements transformed by the function. Here it will take each element from our modified &lt;code&gt;argv&lt;/code&gt; aggregate and concatenates them with &lt;code&gt;&quot; &quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;step&lt;/code&gt; takes an aggregate and a quoted function, and executes the function once for each element of the aggregate. In this case, I call &lt;code&gt;putchars&lt;/code&gt; for each string.&lt;/p&gt;
&lt;p&gt;Thus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./hello.joy hello world
hello world 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ve been using the resources found &lt;a href=&quot;https://hypercubed.github.io/joy/joy.html&quot;&gt;here&lt;/a&gt; which have been most useful at making this short program work.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/joy-arguments</id>
<link href="https://erikarow.land/notes/joy-arguments" />
<title>A Joy to Work With</title>
<updated>2023-10-02T00:00:00+00:00</updated>
<dc:date>2023-09-17T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Writing-From-a-Learning-Firehose&quot;&gt;
&lt;h1&gt;Writing From a Learning Firehose&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m attending the &lt;a href=&quot;https://www.recurse.com/&quot;&gt;Recurse Center&lt;/a&gt; (remotely).&lt;/p&gt;
&lt;p&gt;I value writing things down because I don&amp;rsquo;t trust my memory to retain the information that I&amp;rsquo;ve learned.
Writing everything down from the diversity of people and the pace of learning from the recurse center is difficult.&lt;/p&gt;
&lt;p&gt;I had a great conversation about how to write about the things that you&amp;rsquo;re learning or working on.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Special thank you to Aditya, Mike, and Rachel for their generous ideas!&lt;/span&gt;&lt;/span&gt;
These are some of my takeaways from that conversation.&lt;/p&gt;
&lt;section id=&quot;Spool-Brain-to-Disk&quot;&gt;
&lt;h2&gt;Spool Brain to Disk&lt;/h2&gt;
&lt;p&gt;Or, take notes as you go.&lt;/p&gt;
&lt;p&gt;Aditya uses git commit messages to record his thoughts in the moment.
Anything that would want to refer back to later, ends up in the git messages.
It acts an append-only buffer, timestamped with when specific notes were written.&lt;/p&gt;
&lt;p&gt;I plan to use &lt;a href=&quot;/notes/jrnl&quot;&gt;&lt;code&gt;jrnl&lt;/code&gt;&lt;/a&gt; to do the same, with a custom journal for a writing project I&amp;rsquo;m working on.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Lower-the-Bar&quot;&gt;
&lt;h2&gt;Lower the Bar&lt;/h2&gt;
&lt;p&gt;Write less and be okay with it.&lt;/p&gt;
&lt;p&gt;Rachel suggested writing for 5 minutes, 1 minute. Make it a tiny habit to start writing.&lt;/p&gt;
&lt;p&gt;Mike uses writing as accountability. A short summary of what he did posted in a public blog post.&lt;/p&gt;
&lt;p&gt;In both cases, the lesson is to write less, and to be okay with hitting publish sooner rather than later.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Pair-and-Share&quot;&gt;
&lt;h2&gt;Pair and Share&lt;/h2&gt;
&lt;p&gt;I often learn a lot when I&amp;rsquo;m working with someone else.
This is a technique to better write down discoveries from those sessions.&lt;/p&gt;
&lt;p&gt;Pause every 20 minutes or so to reflect on what you&amp;rsquo;ve learned.
Write everything new down in your intake spool.
Then share everything you wrote down with your partner(s).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Conclusion&quot;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
Spool your brain
&lt;/li&gt;
&lt;li&gt;
Lower the bar
&lt;/li&gt;
&lt;li&gt;
Pair and share
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I plan to use these suggestions to write about what I learn.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/articles/learning-from-a-firehose</id>
<link href="https://erikarow.land/articles/learning-from-a-firehose" />
<title>Writing From a Learning Firehose</title>
<updated>2023-10-02T00:00:00+00:00</updated>
<dc:date>2023-07-03T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Percent-Encoding-URLs&quot;&gt;
&lt;h1&gt;Percent Encoding URLs&lt;/h1&gt;
&lt;p&gt;I use &lt;a href=&quot;/notes/djot&quot;&gt;djot&lt;/a&gt; for the markup on my static site generator.
In djot, the link syntax looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-djot&quot;&gt;[link text](http://example.com)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works fine for most links, but certain links that include parenthesis, it breaks. This is mostly a problem for Wikipedia, which uses parenthesis for disambiguation of topics. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-djot&quot;&gt;[Variety](https://en.wikipedia.org/wiki/Variety_(cybernetics)#Law_of_requisite_variety)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As written, this will break the link, since &lt;code&gt;djot&lt;/code&gt; will parse the first closing &lt;code&gt;)&lt;/code&gt; as the end of the URL, which is not the complete link. This is because, &lt;a href=&quot;https://github.com/jgm/djot#rationale&quot;&gt;by design&lt;/a&gt;, &lt;code&gt;djot&lt;/code&gt; parses markup in linear time without backtracking.&lt;/p&gt;
&lt;section id=&quot;Percent-Encoding-Parenthesis&quot;&gt;
&lt;h2&gt;Percent Encoding Parenthesis&lt;/h2&gt;
&lt;p&gt;This is where &lt;a href=&quot;https://en.wikipedia.org/wiki/Percent-encoding&quot;&gt;Percent Encoding&lt;/a&gt; comes in. Percent encoding is a method specified in the URI specification that allows for the encoding of arbitrary data in a URI.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;If you would like to read the details, they seem to be specified &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3986#section-2.1&quot;&gt;here&lt;/a&gt; in RFC 3986 Uniform Resource Identifier (URI): Generic Syntax.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Specifically, I needed to encode &lt;code&gt;)&lt;/code&gt; as &lt;code&gt;%29&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Technically, &lt;code&gt;(&lt;/code&gt; is also a reserved character and should be escaped, but I don&amp;rsquo;t run into any issues with &lt;code&gt;djot&lt;/code&gt; with that character, so I leave it out here.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Using my link from before, that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-djot&quot;&gt;[Variety](https://en.wikipedia.org/wiki/Variety_(cybernetics%29#Law_of_requisite_variety)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I use this markup: &lt;a href=&quot;https://en.wikipedia.org/wiki/Variety_(cybernetics%29#Law_of_requisite_variety&quot;&gt;Variety&lt;/a&gt;, I correctly get the link to the Wikipedia article.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Elixir-URI-encoding&quot;&gt;
&lt;h2&gt;Elixir URI encoding&lt;/h2&gt;
&lt;p&gt;When I first learned about Percent Encoding, I quickly found the &lt;code&gt;URI.encode/1&lt;/code&gt; function in Elixir. To my dismay, it didn&amp;rsquo;t correctly escape parenthesis:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex()&amp;gt; URI.encode(&quot;(hello)&quot;)
&quot;(hello)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Frustrated, I continued escaping my links for &lt;code&gt;djot&lt;/code&gt; by hand.&lt;/p&gt;
&lt;p&gt;Today, I re-read the documentation of &lt;code&gt;URI.encode&lt;/code&gt; and found a line that I previously missed&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Full documentation &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/URI.html#encode/2&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This function also accepts a predicate function as an optional argument. If
passed, this function will be called with each byte in string as its argument
and should return a truthy value (anything other than false or nil) if the
given byte should be left as is, or return a falsy value (false or nil) if the
character should be escaped. Defaults to URI.char_unescaped?/1.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The documentation for &lt;code&gt;URI.char_unescaped?/1&lt;/code&gt; explains that it is deliberately escaping the minimum required and purposely leaving reserved characters unescaped:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Checks if character is allowed unescaped in a URI.&lt;/p&gt;
&lt;p&gt;This is the default used by URI.encode/2 where both reserved (char_reserved?/1)
and unreserved characters (char_unreserved?/1) are kept unescaped.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It also hints at a better predicate function for &lt;code&gt;URI.encode&lt;/code&gt;, &lt;code&gt;URI.char_unreserved?/1&lt;/code&gt;, which escapes the parenthesis like I need:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex()&amp;gt; URI.encode(&quot;(hello)&quot;, &amp;amp;URI.char_unreserved?/1)
&quot;%28hello%29&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;djot&lt;/code&gt;&amp;rsquo;s linear parsing forces it to assume that the first &lt;code&gt;)&lt;/code&gt; it encounters is the end of a URL.&lt;/p&gt;
&lt;p&gt;Using percent encoding, I can encode &lt;code&gt;)&lt;/code&gt; as &lt;code&gt;%29&lt;/code&gt;, which solves the &lt;code&gt;djot&lt;/code&gt; issue while allowing the browser to route the URL correctly.&lt;/p&gt;
&lt;p&gt;Elixir&amp;rsquo;s &lt;code&gt;URI.encode&lt;/code&gt; doesn&amp;rsquo;t escape parenthesis by default, but does allow an alternate predicate function that does.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I wrote a &lt;a href=&quot;https://paste.sr.ht/~erikareads/fec63bb983397be405a40e3a7a17bd775dde9add&quot;&gt;short script&lt;/a&gt; that I can call using &lt;a href=&quot;/notes/kakoune&quot;&gt;kakoune&lt;/a&gt;&amp;rsquo;s pipe command. Since it has no dependencies, the startup time is minimal, but I may rewrite it in a faster startup time language later.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/percent-encoding</id>
<link href="https://erikarow.land/notes/percent-encoding" />
<title>Percent Encoding URLs</title>
<updated>2023-09-19T00:00:00+00:00</updated>
<dc:date>2023-09-19T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Include-Diff-in-Git-Commit-Editor&quot;&gt;
&lt;h1&gt;Include Diff in Git Commit Editor&lt;/h1&gt;
&lt;p&gt;Running &lt;code&gt;git commit&lt;/code&gt; with the &lt;code&gt;--verbose&lt;/code&gt; flag allows me to include the diff that&amp;rsquo;s being applied by the commit inside the editor where I&amp;rsquo;m writing my commit message. This makes it easier for me to describe the changes that were being made, since I can scroll down in my editor to see them&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more in the documentation for &lt;a href=&quot;https://www.git-scm.com/docs/git-commit&quot;&gt;&lt;code&gt;git-commit&lt;/code&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Even though the lines aren&amp;rsquo;t prefixed with &lt;code&gt;#&lt;/code&gt;, they are ignored by &lt;code&gt;git-commit&lt;/code&gt; when submitting my commit message.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Please enter the commit message for your changes. Lines starting
# with &#x27;#&#x27; will be ignored, and an empty message aborts the commit.
#
# On branch main
#
# Initial commit
#
# Changes to be committed:
#	new file:   hello.txt
#
# ------------------------ &amp;gt;8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
diff --git a/hello.txt b/hello.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/hello.txt
@@ -0,0 +1 @@
+hello world
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be set to on by default in the config using &lt;code&gt;commit.verbose = true&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read (a little) more in the docs &lt;a href=&quot;https://www.git-scm.com/docs/git-commit#Documentation/git-commit.txt-commitverbose&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Or as it shows up in my global config:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[commit]
	verbose = true
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/git-commit-diff</id>
<link href="https://erikarow.land/notes/git-commit-diff" />
<title>Include Diff in Git Commit Editor</title>
<updated>2023-09-10T00:00:00+00:00</updated>
<dc:date>2023-09-10T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Temporary-Short-Names&quot;&gt;
&lt;h1&gt;Temporary Short Names&lt;/h1&gt;
&lt;p&gt;When writing code, I prefer to use the full name of something to retain context and design decisions established by that name. However, there are cases where using a name many times in rapid succession becomes tedious, bordering on line noise. 
In those situations, it may make sense to use a temporary alias or short name to keep code legible.&lt;/p&gt;
&lt;p&gt;Here are a couple examples, one in Elixir and one in Rust, of how you can do that:&lt;/p&gt;
&lt;section id=&quot;Rust---Enum-Alias&quot;&gt;
&lt;h2&gt;Rust - Enum Alias&lt;/h2&gt;
&lt;p&gt;If you have a long Enum name like this&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Credit to &lt;a href=&quot;https://www.youtube.com/watch?v=8j_FbjiowvE&quot;&gt;Logan Smith&lt;/a&gt; for introducing me the following trick. Go watch his video to hear more about the reasoning to prefer an alias over a &lt;code&gt;*&lt;/code&gt; import, as well as other opinions on Rust. (This Enum suggestion is point 2 in the video).&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;enum DecidedlyLongEnumNameHere {
  VariantX,
  VariantY,
  VariantZ,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doing an exhaustive pattern match on that Enum becomes tedious:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;match enum {
  DecidedlyLongEnumNameHere::VariantX =&amp;gt; x(),
  DecidedlyLongEnumNameHere::VariantY =&amp;gt; y(),
  DecidedlyLongEnumNameHere::VariantZ =&amp;gt; z(),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust lets you do a &lt;code&gt;use&lt;/code&gt; declaration inside of a function, so you can create a short alias like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use DecidedlyLongEnumNameHere as D;
match enum {
  D::VariantX =&amp;gt; x(),
  D::VariantY =&amp;gt; y(),
  D::VariantZ =&amp;gt; z(),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The alias has the same scope as where you&amp;rsquo;ve used it, and is declared right next to its use, so context from the name is retained.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Elixir---Scoped-Aliases&quot;&gt;
&lt;h2&gt;Elixir - Scoped Aliases&lt;/h2&gt;
&lt;p&gt;In Elixir, you may have a similar problem with long Module or Struct names&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Or both, since structs are named after their creating module, and that module often defines functions useful to that struct.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def my_fun do
  [1, 2, 3]
  |&amp;gt; OverlyLongModuleName.fun1()
  |&amp;gt; OverlyLongModuleName.fun2()
  |&amp;gt; OverlyLongModuleName.fun3()
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I prefer not to use a module wide short name, since that obscures the calling code by disconnecting that code from information important to understand its purpose.&lt;/p&gt;
&lt;p&gt;Elixir supports lexical scope on &lt;code&gt;alias&lt;/code&gt; and &lt;code&gt;import&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Check out &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.SpecialForms.html#alias/2-lexical-scope&quot;&gt;hexdocs&lt;/a&gt; for more information.&lt;/span&gt;&lt;/span&gt;, so you can do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def my_fun do
  alias OverlyLongModuleName, as: O

  [1, 2, 3]
  |&amp;gt; O.fun1()
  |&amp;gt; O.fun2()
  |&amp;gt; O.fun3()
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows for code to be shortened while retaining proximal knowledge about module context.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t tried either of these in collaborative codebases, but it&amp;rsquo;s nice to know that both are possible.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/temporary-short-names</id>
<link href="https://erikarow.land/notes/temporary-short-names" />
<title>Temporary Short Names</title>
<updated>2023-08-31T00:00:00+00:00</updated>
<dc:date>2023-08-31T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Legible-Timeouts-with-Erlangs-timer&quot;&gt;
&lt;h1&gt;Legible Timeouts with Erlang&amp;rsquo;s &lt;code&gt;timer&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;By convention, timeouts in Erlang (and Elixir) are set in units of milliseconds. However, this isn&amp;rsquo;t type checked by either language, so you end up with magic integers for timeouts throughout a codebase.&lt;/p&gt;
&lt;p&gt;While both Erlang and Elixir support underscores in numbers for readability: &lt;code&gt;5_000&lt;/code&gt;, you&amp;rsquo;re still expected to know that timeouts are in milliseconds.&lt;/p&gt;
&lt;section id=&quot;Enter-timer&quot;&gt;
&lt;h2&gt;Enter &lt;code&gt;timer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Erlang&amp;rsquo;s &lt;a href=&quot;https://www.erlang.org/doc/man/timer.html&quot;&gt;&lt;code&gt;timer&lt;/code&gt;&lt;/a&gt; provides legible helper functions for expressing timeouts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;timer:seconds/1

timer:minutes/1

timer:hours/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each takes an integer and converts it from the stated time to milliseconds.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;timer&lt;/code&gt; also provides &lt;code&gt;timer:hms/3&lt;/code&gt; for hours, minutes, and seconds, returning their sum in milliseconds.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Using-timer-in-Elixir&quot;&gt;
&lt;h2&gt;Using &lt;code&gt;:timer&lt;/code&gt; in Elixir&lt;/h2&gt;
&lt;p&gt;Elixir supports seamless integration of Erlang standard library functions, though the syntax is a bit different:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;:timer.seconds(5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So you can replace&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;ve considered using an opaque type to force the use of legible functions, but that would involve wrapping every function in Erlang and Elixir that uses a timeout, which isn&amp;rsquo;t practical.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Process.sleep(5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Process.sleep(:timer.seconds(5))
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaway&quot;&gt;
&lt;h2&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;Next time you need to set a timeout in Erlang or Elixir, consider using &lt;code&gt;timer&lt;/code&gt; to embed your design decisions and communicate without magic numbers.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Zach for pointing me to &lt;code&gt;timer&lt;/code&gt;!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/legible-timeouts-erlang</id>
<link href="https://erikarow.land/notes/legible-timeouts-erlang" />
<title>Legible Timeouts with Erlangs timer</title>
<updated>2023-08-28T00:00:00+00:00</updated>
<dc:date>2023-08-28T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Set-null-Placeholder-in-PostgreSQL-psql&quot;&gt;
&lt;h1&gt;Set null Placeholder in PostgreSQL psql&lt;/h1&gt;
&lt;p&gt;By default, &lt;code&gt;psql&lt;/code&gt; outputs &lt;code&gt;null&lt;/code&gt; as nothing, which is easily mistaken for an empty string.&lt;/p&gt;
&lt;p&gt;You can use&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about the available &lt;code&gt;psql&lt;/code&gt; commands &lt;a href=&quot;https://www.postgresql.org/docs/current/app-psql.html&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-psql&quot;&gt;\pset null &#x27;&amp;lt;chosen alternative&amp;gt;&#x27;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This seems to be tied to a particular session of &lt;code&gt;psql&lt;/code&gt; as it was reset when I restarted the &lt;code&gt;psql&lt;/code&gt; session.&lt;/p&gt;
&lt;section id=&quot;Unicode-tangent&quot;&gt;
&lt;h2&gt;Unicode tangent&lt;/h2&gt;
&lt;p&gt;The impetus for finding this command came from seeing &lt;code&gt;¤&lt;/code&gt; used as a null placeholder in &amp;ldquo;The Art of PostgreSQL&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It is &lt;code&gt;U+00A4 Currency Sign&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more about the unicode &lt;a href=&quot;https://codepoints.net/U+00A4&quot;&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt; used to denote an unspecified currency. I&amp;rsquo;ve never seen the symbol before, but apparently it is common enough to be in the &lt;a href=&quot;https://en.wikipedia.org/wiki/Currency_sign_(typography%29&quot;&gt;International Reference Variant of ASCII&lt;/a&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to Jeff for exploring PostgreSQL with me!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/postgres-null-placeholder</id>
<link href="https://erikarow.land/notes/postgres-null-placeholder" />
<title>Set null Placeholder in PostgreSQL psql</title>
<updated>2023-08-26T00:00:00+00:00</updated>
<dc:date>2023-08-26T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;My-Favorite-Elixir-Discovery---Access&quot;&gt;
&lt;h1&gt;My Favorite Elixir Discovery - Access&lt;/h1&gt;
&lt;p&gt;A while ago, I read Hillel Wayne&amp;rsquo;s&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://buttondown.email/hillelwayne/archive/search-less-browse-more-7595/&quot;&gt;source&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; suggestion to &amp;ldquo;Search less, browse more&amp;rdquo;. Specifically to systemically go through the the information available for your chosen tools, rather than searching for specific answers to questions as they arise. This is the story of what I found when I started browsing through Elixir&amp;rsquo;s documentation.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;As found on &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Kernel.html&quot;&gt;HexDocs&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;But first, a diversion into:&lt;/p&gt;
&lt;section id=&quot;GraphQL-queries&quot;&gt;
&lt;h2&gt;GraphQL queries&lt;/h2&gt;
&lt;p&gt;One of the advantages of GraphQL is that you specify the structure that you&amp;rsquo;re querying with your query. You specify the edges and nodes of the data that you want, and it&amp;rsquo;s delivered in JSON with exactly that schema. However, this can get unwieldy if the accessible starting point is far away in the graph from the data you need.&lt;/p&gt;
&lt;p&gt;For example, here is a query accessing &amp;lt;meetup.com&amp;gt;&amp;rsquo;s API searching for Online Elixir Events hosted by Groups&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;A lot of Elixir meetups went online during the pandemic, but Meetup&amp;rsquo;s search made them hard to find.&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Latitude: &lt;code&gt;-48.876667&lt;/code&gt; and Longitude: &lt;code&gt;-123.393333&lt;/code&gt; points to &lt;a href=&quot;https://en.wikipedia.org/wiki/Extremes_on_Earth#Oceanic&quot;&gt;Point Nemo&lt;/a&gt; the most distant point of ocean from land.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gql&quot;&gt;{
  keywordSearch(
    input: { first: 1000 }
    filter: {
      query: &quot;elixir&quot;
      lat: -48.876667
      lon: -123.393333
      source: GROUPS
      radius: 100
      eventType: ONLINE
    }
  ) {
    edges {
      node {
        result {
          ... on Group {
            name
            unifiedEvents {
              count
              edges {
                node {
                  title
                  isOnline
                  eventUrl
                  description
                  dateTime
                  timezone
                  group {
                    name
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the nested curly braces at the end. I can get the data I need, and I know the structure that it&amp;rsquo;s in, but the data I care about is hidden by a nest of indirection.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how I first attempted to unpack the data I needed:&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Unpacking-GraphQL-in-Elixir&quot;&gt;
&lt;h2&gt;Unpacking GraphQL in Elixir&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def main() do
  Neuron.Config.set(url: &quot;https://api.meetup.com/gql&quot;)
  {:ok, query_results} = File.read!(&quot;elixir.gql&quot;) |&amp;gt; Neuron.query()

   results = query_results.body[&quot;data&quot;][&quot;keywordSearch&quot;][&quot;edges&quot;] 
     |&amp;gt; Enum.filter(fn elem -&amp;gt; elem[&quot;node&quot;][&quot;result&quot;][&quot;unifiedEvents&quot;][&quot;count&quot;] &amp;gt; 0 end) 
     |&amp;gt; Enum.map(fn elem -&amp;gt; elem[&quot;node&quot;][&quot;result&quot;][&quot;unifiedEvents&quot;][&quot;edges&quot;] end) 
     |&amp;gt; Enum.concat()
     |&amp;gt; Enum.map(fn elem -&amp;gt; elem[&quot;node&quot;] end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is only getting the maps of data that I care about, it doesn&amp;rsquo;t include additional work to do filtering that the API didn&amp;rsquo;t provide sufficient granularity to do before the query&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn5&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn5&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Neuron is an Elixir GraphQL client: &lt;a href=&quot;https://hexdocs.pm/neuron/readme.html&quot;&gt;https://hexdocs.pm/neuron/readme.html&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Part of what makes it awkward is that we alternate between nodes, which are parsed as maps, and edges, which deserialize as lists.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Access-a-better-alternative&quot;&gt;
&lt;h2&gt;Access, a better alternative?&lt;/h2&gt;
&lt;p&gt;This brings me back to browsing the Elixir documentation. My first inkling that there might be a better way arrived with &lt;code&gt;Kernel.get_in/2&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn6&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn6&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Read more &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Kernel.html#get_in/2&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;. &lt;code&gt;get_in/2&lt;/code&gt; gets a value from a nested structure, I have one of those! It takes a data structure and a list of keys, and uses the Access behaviour&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn7&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn7&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I wondered why Access was implemented as a Behaviour and not a Protocol. &lt;a href=&quot;https://stackoverflow.com/questions/33704618/why-is-elixirs-access-behaviour-not-a-protocol&quot;&gt;It turns out&lt;/a&gt; that it comes down to performance, Access is invoked far more than any protocol functionality in Elixir, and it was becoming a bottleneck. So they switched it to a Behaviour, which is built right into the Erlang/OTP ecosystem, and is optimized with first-class support.&lt;/span&gt;&lt;/span&gt; to extract a value.&lt;/p&gt;
&lt;p&gt;Access is what powers the &lt;code&gt;thing[&quot;squareBracket&quot;]&lt;/code&gt; syntax, so we were already using it. The real power of the module comes from special functions in the Access module&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn8&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn8&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;read more about Access &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Access.html&quot;&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;. The &lt;code&gt;get_in/2&lt;/code&gt; function takes more than just atom or string keys, it can also take functions that can process our GraphQL Edges. Let&amp;rsquo;s talk about three:&lt;/p&gt;
&lt;section id=&quot;Accessall0&quot;&gt;
&lt;h3&gt;&lt;code&gt;Access.all/0&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Access.html#all/0&quot;&gt;&lt;code&gt;Access.all/0&lt;/code&gt;&lt;/a&gt; accesses all elements of a list.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex()&amp;gt; books = [
         %{
           name: &quot;Naming Things&quot;, 
           url: &quot;https://www.namingthings.co/&quot;
         },
         %{
           name: &quot;Essence of Software&quot;, 
           url: &quot;https://essenceofsoftware.com/&quot;
          }
        ]

iex()&amp;gt; get_in(books, [Access.all(), :name])
[&quot;Naming Things&quot;, &quot;Essence of Software&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Accessfilter1&quot;&gt;
&lt;h3&gt;&lt;code&gt;Access.filter/1&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Access.html#filter/1&quot;&gt;&lt;code&gt;Access.filter/1&lt;/code&gt;&lt;/a&gt; access all elements of a list that match a provided predicate function.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex()&amp;gt; books = [
         %{
           name: &quot;Naming Things&quot;, 
           url: &quot;https://www.namingthings.co/&quot;
         },
         %{
           name: &quot;Essence of Software&quot;, 
           url: &quot;https://essenceofsoftware.com/&quot;
          }
        ]

iex()&amp;gt; get_in(
  books, 
  [
    Access.filter(
      &amp;amp;String.starts_with?(&amp;amp;1.name, &quot;N&quot;)
    ), 
    :name
  ]
)
[&quot;Naming Things&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Accesskey2&quot;&gt;
&lt;h3&gt;&lt;code&gt;Access.key/2&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Access.html#key/2&quot;&gt;&lt;code&gt;Access.key/2&lt;/code&gt;&lt;/a&gt; allows you to access the given key in a map or struct. This seems superfluous, but in Elixir, Structs don&amp;rsquo;t implement the Access behaviour by default. This means that you access keys with the &lt;code&gt;.&lt;/code&gt; syntax, but not the &lt;code&gt;[]&lt;/code&gt; syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;defmodule MyStruct do
  defstruct [:name]
end

iex()&amp;gt; my_struct = %MyStruct{name: &quot;A name&quot;}
iex()&amp;gt; my_struct.name
&quot;A name&quot;
iex()&amp;gt; my_struct[:name]
** (UndefinedFunctionError) function 
MyStruct.fetch/2 is undefined (MyStruct does not 
implement the Access behaviour. If you are using 
get_in/put_in/update_in, you can specify the 
field to be accessed using Access.key!/1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error message hints at the usefulness of &lt;code&gt;Access.key/2&lt;/code&gt;, though it recommends the version that can throw an error: &lt;code&gt;Access.key!/1&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex() get_in(my_struct, [Access.key(:name)])
&quot;A name&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is extremely useful for structs generated by other Elixir libraries&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn9&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn9&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I personally found this useful for access nested structures preloaded from &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.html&quot;&gt;Ecto&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Returning-to-GraphQL&quot;&gt;
&lt;h2&gt;Returning to GraphQL&lt;/h2&gt;
&lt;p&gt;With Access in hand, I can refactor my nested access call from earlier&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn10&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn10&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I can skip my earlier use of filter since &lt;code&gt;Enum.concat/1&lt;/code&gt; behaves nicely with empty lists.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def main() do
  Neuron.Config.set(url: &quot;https://api.meetup.com/gql&quot;)
  {:ok, query_results} = File.read!(&quot;elixir.gql&quot;) |&amp;gt; Neuron.query()

  results = get_in(
    query_results, 
    [
      Access.key(:body), 
      &quot;data&quot;, 
      &quot;keywordSearch&quot;, 
      &quot;edges&quot;, 
      Access.all(), 
      &quot;node&quot;, 
      &quot;result&quot;, 
      &quot;unifiedEvents&quot;, 
      &quot;edges&quot;, 
      Access.all(), 
      &quot;node&quot;
     ]
  ) |&amp;gt; Enum.concat()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This shows us exactly how indirect the original data was. Now the structure is easy to see and modify.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Takeaways&quot;&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Access&lt;/code&gt; provides a clean way to access data in nested data structures. &lt;code&gt;Access.key&lt;/code&gt; provides a way to access structs. &lt;code&gt;Access.all&lt;/code&gt; and &lt;code&gt;Access.filter/1&lt;/code&gt; provide ways to handle lists in the middle of a data structure&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn11&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn11&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;ve heard that this style of accessors is referred to as Functional Lenses, and other programming languages have implementations or libraries supporting this kind access.&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Here, I only needed to access the nested data, but Elixir&amp;rsquo;s &lt;code&gt;Kernel&lt;/code&gt; provides functions for &lt;code&gt;get_and_update_in/3&lt;/code&gt;, &lt;code&gt;pop_in/2&lt;/code&gt;, &lt;code&gt;put_in/3&lt;/code&gt; for changing the data in that nested structure. Check them out: &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.0/Kernel.html&quot;&gt;https://hexdocs.pm/elixir/1.15.0/Kernel.html&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/articles/favorite-elixir-discovery</id>
<link href="https://erikarow.land/articles/favorite-elixir-discovery" />
<title>My Favorite Elixir Discovery - Access</title>
<updated>2023-08-23T00:00:00+00:00</updated>
<dc:date>2023-08-23T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;i3-Window-Manager-Space-Mode&quot;&gt;
&lt;h1&gt;i3 Window Manager Space Mode&lt;/h1&gt;
&lt;p&gt;When I tried &lt;a href=&quot;https://www.spacemacs.org/&quot;&gt;Spacemacs&lt;/a&gt;, the one thing I really liked was the &amp;ldquo;leader&amp;rdquo; key setup they had around the spacebar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://i3wm.org/&quot;&gt;i3 window manager&lt;/a&gt; supports arbitrary modes, which can have their own keybinds. This is how I currently have a small &amp;ldquo;space-mode&amp;rdquo; setup in my i3 config&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The &lt;code&gt;$reset&lt;/code&gt; is vital here, otherwise you&amp;rsquo;ll be stuck in &amp;ldquo;space-mode&amp;rdquo; forever.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set $reset mode &quot;default&quot;

bindsym $mod+space mode &quot;space-mode&quot;

mode &quot;space-mode&quot; {
    bindsym space exec --no-startup-id dmenu_run; $reset
    bindsym $mod+space exec --no-startup-id dmenu_run; $reset
    bindsym Escape $reset
    bindym Return exec alacritty; $reset
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/i3wm-space-mode</id>
<link href="https://erikarow.land/notes/i3wm-space-mode" />
<title>i3 Window Manager Space Mode</title>
<updated>2023-08-22T00:00:00+00:00</updated>
<dc:date>2023-08-22T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Adding-RSS-Feed-Link-Tag&quot;&gt;
&lt;h1&gt;Adding RSS Feed Link Tag&lt;/h1&gt;
&lt;p&gt;Recently, I added some Atom (RSS)&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/3489578/which-is-most-used-rss-or-atom-and-which-one-is-better-to-build-from&quot;&gt;https://stackoverflow.com/questions/3489578/which-is-most-used-rss-or-atom-and-which-one-is-better-to-build-from&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; feeds to my website.
I wanted to make sure that I appropriately linked them in my website&amp;rsquo;s header.&lt;/p&gt;
&lt;p&gt;The solution is to use a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Link documentation: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; element:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link 
   rel=&quot;alternate&quot; 
   title=&quot;Erika Rowland Combined Feed&quot; 
   type=&quot;application/atom+xml&quot; 
   href=&quot;https://erikarow.land/combined.xml&quot;
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have multiple feeds so I wanted to make sure I knew how to appropriately link all of them. It seems that it&amp;rsquo;s valid to simply add a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element for each feed:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://webmasters.stackexchange.com/questions/102139/can-a-website-have-multiple-rss-feeds-how-would-the-link-and-channel-elemen&quot;&gt;https://webmasters.stackexchange.com/questions/102139/can-a-website-have-multiple-rss-feeds-how-would-the-link-and-channel-elemen&lt;/a&gt;&lt;/p&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/adding-rss-feed-link-tag</id>
<link href="https://erikarow.land/notes/adding-rss-feed-link-tag" />
<title>Adding RSS Feed Link Tag</title>
<updated>2023-08-11T00:00:00+00:00</updated>
<dc:date>2023-08-11T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Edit-the-Clipboard&quot;&gt;
&lt;h1&gt;Edit the Clipboard&lt;/h1&gt;
&lt;p&gt;I recently wanted to write some code in a Github issue,
but while Github Flavored Markdown supports code snippets,
the web editor has a variable spaced font that makes writing formatted code difficult.&lt;/p&gt;
&lt;section id=&quot;Enter-vipe&quot;&gt;
&lt;h2&gt;Enter &lt;code&gt;vipe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/notes/vipe&quot;&gt;&lt;code&gt;vipe&lt;/code&gt;&lt;/a&gt; is a tool from &lt;a href=&quot;https://joeyh.name/code/moreutils/&quot;&gt;moreutils&lt;/a&gt; that allows you insert an editor into a unix pipe.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vipe&lt;/code&gt; will create a temporary file with anything passed from standard input (empty if invoked directly) and open &lt;code&gt;$EDITOR&lt;/code&gt; on that file.
Anything that saved in that file when the editor closes is piped to standard output.&lt;/p&gt;
&lt;p&gt;To solve my Github problem, I realized that I could invoke:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ vipe | xclip -selection clipboard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which let me type my code snippet in my editor of choice,
then copied that snippet onto my clipboard.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xclip -out&lt;/code&gt; can be used to output the current state of the clipboard, so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ xclip -out | vipe | xclip -selection clipboard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;can be used to modify the current clipboard in an editor.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/edit-the-clipboard</id>
<link href="https://erikarow.land/notes/edit-the-clipboard" />
<title>Edit the Clipboard</title>
<updated>2023-08-08T00:00:00+00:00</updated>
<dc:date>2023-08-08T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;An-Unlinked-Adventure&quot;&gt;
&lt;h1&gt;An Unlinked Adventure&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve been working on my new tool &lt;a href=&quot;https://github.com/erikareads/maru&quot;&gt;&lt;code&gt;maru&lt;/code&gt;&lt;/a&gt;, to get it polished for release. To that end, I decided to look at &lt;a href=&quot;https://opensource.axo.dev/cargo-dist/&quot;&gt;&lt;code&gt;cargo-dist&lt;/code&gt;&lt;/a&gt; a tool that aims to help with release engineering for Rust projects.
Since &lt;code&gt;maru&lt;/code&gt; is a Rust CLI, it seemed like a great fit.&lt;/p&gt;
&lt;p&gt;This is the story of how the interaction between cross-compilation and NixOS led to a rabbit hole of dynamic linking on linux.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thank you to Jeff for pairing with me as we ventured into this rabbit hole.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;cargo-dist&quot;&gt;
&lt;h2&gt;&lt;code&gt;cargo-dist&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cargo dist init&lt;/code&gt; will generate a github action to handle automatic release creation on Github when tags update. For &lt;code&gt;maru&lt;/code&gt;, I was missing &lt;code&gt;repository = ...&lt;/code&gt; in my &lt;code&gt;Cargo.toml&lt;/code&gt;, which &lt;code&gt;cargo-dist&lt;/code&gt; noticed and prompted me to fix.&lt;/p&gt;
&lt;p&gt;After adding:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;repository = &quot;https://github.com/erikareads/maru&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to my &lt;code&gt;Cargo.toml&lt;/code&gt;, &lt;code&gt;cargo dist init&lt;/code&gt; helpfully generated a github action workflow and updated the &lt;code&gt;Cargo.toml&lt;/code&gt; with configuration metadata. I chose to use the &lt;code&gt;shell&lt;/code&gt; installer, to see how it worked for &lt;code&gt;maru&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Previously, I had run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo install --git &quot;https://github.com/erikareads/maru&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which compiled &lt;code&gt;maru&lt;/code&gt; locally, which worked on my NixOS machine.&lt;/p&gt;
&lt;p&gt;After generating the Github action yaml with &lt;code&gt;cargo-dist&lt;/code&gt;, I committed the changes and pushed a tag.
To my delight, the Github action automatically compiled &lt;code&gt;maru&lt;/code&gt; for three different architectures and generated a release.&lt;/p&gt;
&lt;p&gt;However, when I downloaded the &lt;code&gt;maru-x86_64-unknown-linux-gnu.tar.xz&lt;/code&gt;, unpacked it, and ran &lt;code&gt;./maru&lt;/code&gt; I got this error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./maru
bash: ./maru: cannot execute: required file not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uh oh, what required file isn&amp;rsquo;t working? This is where the linking adventure really began.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;The-adventure-begins---strings&quot;&gt;
&lt;h2&gt;The adventure begins - &lt;code&gt;strings&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Jeff suggested using &lt;code&gt;strings&lt;/code&gt; to see the difference between my working locally compiled version and the broken downloaded version.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;diff &amp;lt;(strings ~/.cargo/bin/maru) &amp;lt;(strings ~/Downloads/maru-x86_64-unknown-linux-gnu/maru ) | less
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From which we found:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt; /nix/store/yaz7pyf0ah88g2v505l38n0f3wg2vzdj-glibc-2.37-8/lib/ld-linux-x86-64.so.2
---
&amp;gt; /lib64/ld-linux-x86-64.so.2
&amp;gt; libgcc_s.so.1
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh, non-standard NixOS strikes again. I don&amp;rsquo;t yet understand what that difference means, but it&amp;rsquo;s clear that it&amp;rsquo;s at the heart of what&amp;rsquo;s breaking the binary.&lt;/p&gt;
&lt;p&gt;Now that we know that an interaction with NixOS is probably the source of the issue. A search&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I used Duck Duck Go for my searches during this adventure.&lt;/span&gt;&lt;/span&gt; of&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nixos rust cannot execute: required file not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Led to a &lt;a href=&quot;https://matklad.github.io/2022/03/14/rpath-or-why-lld-doesnt-work-on-nixos.html&quot;&gt;matklad article about &lt;code&gt;ld&lt;/code&gt; on NixOS&lt;/a&gt;. There he suggests &lt;code&gt;readelf&lt;/code&gt; as a path forward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ readelf -d ~/Downloads/maru-x86_64-unknown-linux-gnu/maru
Dynamic section at offset 0x16b560 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comparing that with the locally built working version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ readelf -d ~/.cargo/bin/maru
Dynamic section at offset 0x175ea8 contains 32 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x000000000000001d (RUNPATH)            Library runpath: [/nix/store/...]
 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The locally built one has an extra shared library -&amp;gt; the &lt;code&gt;ld&lt;/code&gt; linker that we found different in the &lt;code&gt;strings&lt;/code&gt; output.
In addition, NixOS sets a &lt;code&gt;RUNPATH&lt;/code&gt; that allows the binary to find the shared libraries on NixOS.&lt;/p&gt;
&lt;p&gt;Knowing that &lt;code&gt;ld&lt;/code&gt; is the problem on NixOS, I searched:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;compiled binary doesn&#x27;t work on nixos ld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which led to &lt;a href=&quot;https://blog.thalheim.io/2022/12/31/nix-ld-a-clean-solution-for-issues-with-pre-compiled-executables-on-nixos/&quot;&gt;an article on nix-ld&lt;/a&gt;. Binaries assume the &lt;code&gt;ld&lt;/code&gt; is a fixed location for &lt;code&gt;glibc&lt;/code&gt;, but NixOS breaks that convention. &lt;code&gt;nix-ld&lt;/code&gt; addresses the problem by overriding the &lt;code&gt;RUNPATH&lt;/code&gt; that was set when we compiled locally, even on binaries that where we can&amp;rsquo;t recompile them ourselves.&lt;/p&gt;
&lt;p&gt;Which is great, but I &lt;strong&gt;have&lt;/strong&gt; the source code available, &lt;code&gt;maru&lt;/code&gt; is my project! Is there a way that I can compile &lt;code&gt;maru&lt;/code&gt; such that this linking path problem isn&amp;rsquo;t an issue?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;How-does-ripgrep-do-it&quot;&gt;
&lt;h2&gt;How does ripgrep do it?&lt;/h2&gt;
&lt;p&gt;My first thought was to look at &lt;code&gt;ripgrep&lt;/code&gt;, a known well-distributed Rust CLI. I installed &lt;code&gt;ripgrep&lt;/code&gt; using NixOS, so maybe that handled this issue for me, but I wanted to check. Looking in &lt;code&gt;ripgrep&lt;/code&gt;&amp;lsquo;s &lt;a href=&quot;https://github.com/BurntSushi/ripgrep/releases&quot;&gt;releases&lt;/a&gt;, I see that it *doesn&amp;rsquo;t* compile for &lt;code&gt;unknown-linux-gnu&lt;/code&gt;, but instead for &lt;code&gt;unknown-linux-musl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Downloading this binary of &lt;code&gt;ripgrep&lt;/code&gt;, the invocation works without issue.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;musl&quot;&gt;
&lt;h2&gt;musl?&lt;/h2&gt;
&lt;p&gt;This led me to search for:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rust compile without dynamic linking
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which led to this &lt;a href=&quot;https://stackoverflow.com/questions/31770604/how-to-generate-statically-linked-executables&quot;&gt;stack overflow&lt;/a&gt; question which led me to this answer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rust statically links everything but glibc (and libgcc, iirc) by default.&lt;/p&gt;
&lt;p&gt;If you want to get a 100% statically linked binary, you can use MUSL with 1.1. &lt;a href=&quot;https://github.com/rust-lang/rust/pull/24777&quot;&gt;https://github.com/rust-lang/rust/pull/24777&lt;/a&gt; is the initial support, we hope to make it much easier to use in the future.&lt;/p&gt;
&lt;p&gt;EDIT: It&amp;rsquo;s distributed via &lt;code&gt;rustup&lt;/code&gt; now, so you can add &lt;code&gt;x86_64-unknown-linux-musl&lt;/code&gt; as a target : &lt;code&gt;rustup target add x86_64-unknown-linux-musl&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And then build to this target : &lt;code&gt;cargo build --target=x86_64-unknown-linux-musl&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Linking against &lt;code&gt;musl&lt;/code&gt; will allow &lt;code&gt;maru&lt;/code&gt; to be statically compiled, which should avoid the dynamic linking problem on NixOS.&lt;/p&gt;
&lt;p&gt;After running the relevant &lt;code&gt;rustup&lt;/code&gt; and &lt;code&gt;cargo build&lt;/code&gt; commands, I confirmed that a locally &lt;code&gt;musl&lt;/code&gt; compiled binary worked on my NixOS machine.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Patching-the-generated-github-actions&quot;&gt;
&lt;h2&gt;Patching the generated github actions&lt;/h2&gt;
&lt;p&gt;Now, I don&amp;rsquo;t want to locally compile every binary of &lt;code&gt;maru&lt;/code&gt; for my project, so I needed to update the Github actions in order to do the &lt;code&gt;musl&lt;/code&gt; compile.&lt;/p&gt;
&lt;p&gt;An initial test, just switching out the build target failed, because it didn&amp;rsquo;t have the target environment installed via &lt;code&gt;rustup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The fix was to add a conditional to my Github action workflow:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- name: Maybe install target
  if: ${{ contains(matrix.dist-args, &#x27;musl&#x27;) }}
  run: rustup target add x86_64-unknown-linux-musl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Github actions API exposes a function &lt;code&gt;contains&lt;/code&gt;, which allows us to only run this command on the &lt;code&gt;musl&lt;/code&gt; compilation in the matrix of operating systems. &lt;code&gt;rustup&lt;/code&gt; was already being used to install Rust in the Continuous Integration, so we expected that the &lt;code&gt;rustup target&lt;/code&gt; would work.&lt;/p&gt;
&lt;p&gt;After a few minutes of eagerly waiting for the new version to compile, we confirmed that the &lt;code&gt;musl&lt;/code&gt; binary worked both on NixOS and on Debian.&lt;/p&gt;
&lt;p&gt;This was great, but the &lt;code&gt;shell&lt;/code&gt; installer provided by &lt;code&gt;cargo-dist&lt;/code&gt; no longer worked, since it was looking for the &lt;code&gt;gnu&lt;/code&gt; binary.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Turns out this was a &lt;a href=&quot;https://opensource.axo.dev/cargo-dist/book/installers.html#shell&quot;&gt;known problem&lt;/a&gt; and was mentioned in the limitations/caveats in the documentation. Check out &lt;a href=&quot;https://github.com/axodotdev/cargo-dist/issues/75&quot;&gt;this issue&lt;/a&gt; for discussion on the problem.&lt;/span&gt;&lt;/span&gt; The shell installer checks to see whether &lt;code&gt;glibc&lt;/code&gt; exists on the installing system, which isn&amp;rsquo;t sufficient for NixOS to avoid the problem, but it doesn&amp;rsquo;t switch to &lt;code&gt;musl&lt;/code&gt; if the &lt;code&gt;gnu&lt;/code&gt; binary isn&amp;rsquo;t found in the release.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Results&quot;&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;Thanks to this adventure, &lt;code&gt;maru&lt;/code&gt; is now statically linked for linux systems, and runs without issues straight after download on both NixOS and Debian.&lt;/p&gt;
&lt;p&gt;Jeff and I learned about excellent debugging tools such as &lt;code&gt;readelf&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Also &lt;code&gt;strace&lt;/code&gt; and &lt;code&gt;file&lt;/code&gt; which I didn&amp;rsquo;t mention in the story, since &lt;code&gt;readelf&lt;/code&gt; provided the correct information. &lt;code&gt;file&lt;/code&gt; did share: &lt;code&gt;interpreter /lib64/ld-linux-x86-64.so.2&lt;/code&gt;, which succinctly showed the path.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/articles/an-unlinked-adventure</id>
<link href="https://erikarow.land/articles/an-unlinked-adventure" />
<title>An Unlinked Adventure</title>
<updated>2023-08-06T00:00:00+00:00</updated>
<dc:date>2023-08-06T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Playing-with-SVG&quot;&gt;
&lt;h1&gt;Playing with SVG&lt;/h1&gt;
&lt;p&gt;This week I had a chance to play with SVGs. 
Previously, I&amp;rsquo;ve felt intimidated by generatin graphics with code, 
but I found working with SVGs to be delightful.&lt;/p&gt;
&lt;section id=&quot;Basics---Path&quot;&gt;
&lt;h2&gt;Basics - Path&lt;/h2&gt;
&lt;svg width=&quot;100&quot; height=&quot;100&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;

  &lt;path d=&quot;M 10 10 H 90 V 90 H 10 Z&quot; fill=&quot;transparent&quot; stroke=&quot;black&quot;/&gt;

  &lt;!-- Points --&gt;
  &lt;circle cx=&quot;10&quot; cy=&quot;10&quot; r=&quot;5&quot; fill=&quot;red&quot;/&gt;
  &lt;circle cx=&quot;90&quot; cy=&quot;90&quot; r=&quot;5&quot; fill=&quot;red&quot;/&gt;
  &lt;circle cx=&quot;90&quot; cy=&quot;10&quot; r=&quot;5&quot; fill=&quot;red&quot;/&gt;
  &lt;circle cx=&quot;10&quot; cy=&quot;90&quot; r=&quot;5&quot; fill=&quot;red&quot;/&gt;

&lt;/svg&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;svg width=&quot;100&quot; height=&quot;100&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;

  &amp;lt;path d=&quot;M 10 10 H 90 V 90 H 10 Z&quot; fill=&quot;transparent&quot; stroke=&quot;black&quot;/&amp;gt;

  &amp;lt;!-- Points --&amp;gt;
  &amp;lt;circle cx=&quot;10&quot; cy=&quot;10&quot; r=&quot;5&quot; fill=&quot;red&quot;/&amp;gt;
  &amp;lt;circle cx=&quot;90&quot; cy=&quot;90&quot; r=&quot;5&quot; fill=&quot;red&quot;/&amp;gt;
  &amp;lt;circle cx=&quot;90&quot; cy=&quot;10&quot; r=&quot;5&quot; fill=&quot;red&quot;/&amp;gt;
  &amp;lt;circle cx=&quot;10&quot; cy=&quot;90&quot; r=&quot;5&quot; fill=&quot;red&quot;/&amp;gt;

&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of the more powerful tools that SVG provides is the &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;.
A &lt;code&gt;path&lt;/code&gt; can have attributes, but it&amp;rsquo;s primary driver is &lt;code&gt;d&lt;/code&gt; for data,
which takes a list of &lt;code&gt;Commands&lt;/code&gt;, 
where each command is a composed of a letter and numbers that are that command&amp;rsquo;s parameters.&lt;/p&gt;
&lt;p&gt;Capital Letters signify absolute commands.&lt;/p&gt;
&lt;p&gt;lower case letters signify relative commands.&lt;/p&gt;
&lt;p&gt;In the example above:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M&lt;/code&gt; stands for MoveTo, moving the cursor to the specified point.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;H&lt;/code&gt; stands for Horizontal, drawing a line from the current point to the end &lt;code&gt;x&lt;/code&gt; coordinate.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;V&lt;/code&gt; stands for Vertical, drawing a line from the current point to the end &lt;code&gt;y&lt;/code&gt; coordinate.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Z&lt;/code&gt; stands for ClosePath, closes the current path drawing a line to the initial point.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; allows me to chain these together to draw things, in this case a square.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Space-vs-Comma&quot;&gt;
&lt;h2&gt;Space vs Comma&lt;/h2&gt;
&lt;svg viewBox=&quot;0 0 200 100&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
  &lt;!-- Example of a polyline with commas between point pairs--&gt;
  &lt;polyline points=&quot;0,100 50,25 50,75 100,0&quot; /&gt;
  &lt;!-- now without commas--&gt; 
  &lt;polyline points=&quot;0 100 50 25 50 75 100 0&quot; transform=&quot;translate(100,0)&quot; /&gt;
  &lt;!-- translated so they&#x27;re not on top of each other--&gt;
&lt;/svg&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;svg viewBox=&quot;0 0 200 100&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;
  &amp;lt;!-- Example of a polyline with commas between point pairs--&amp;gt;
  &amp;lt;polyline points=&quot;0,100 50,25 50,75 100,0&quot; /&amp;gt;
  &amp;lt;!-- now without commas--&amp;gt; 
  &amp;lt;polyline points=&quot;0 100 50 25 50 75 100 0&quot; transform=&quot;translate(100,0)&quot; /&amp;gt;
  &amp;lt;!-- translated so they&#x27;re not on top of each other--&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;SVG-Cat&quot;&gt;
&lt;h2&gt;SVG Cat&lt;/h2&gt;
&lt;svg viewBox=&quot;0 0 72 72&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
&lt;g xmlns=&quot;http://www.w3.org/2000/svg&quot; id=&quot;line&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; stroke-miterlimit=&quot;10&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; stroke=&quot;#000&quot;&gt;
    
    &lt;path d=&quot;m12.46 35.74c-2.333 1-4.917 0.8333-4.917 0.8333-1.677 0.1458-3.115-4.01-2.485-4.733l3.318-5.1-1.75-3.417s5.008-1.415 7.883 2.09c0.3444 0.42 0.7943 0.7429 1.279 0.9871 0.0298 0.015 0.0602 0.0302 0.0912 0.0456 2.593 1.289 5.546 1.571 8.385 0.9981 7.222-1.458 14.07-1.37 21.7 2.212 7.625 3.583 14.53-2.25 13.64-7.5-0.793-4.647 3.562-7.583 6.75-5&quot;/&gt;
    &lt;path d=&quot;m16.05 48.82c0.6006-2.206 8.491-3.648 8.491-3.648s3.228-1.201 1.426-4.504&quot;/&gt;&lt;path d=&quot;m18.3 33.24c-1.543 1.834-3.893 4.803-0.44 9.158 0 0-6.756 2.853-6.006 8.033 0 0 0.3624 2.476 2.402 2.402&quot;/&gt;
    &lt;path d=&quot;m23.5 50.03c-1.156 7.254 2.386 6.055 3.017 5.661 1.148-0.7173 1.848-9.854 3.952-11.31 1.592-1.104 8.167-0.3021 8.167-0.3021&quot;/&gt;
    &lt;path d=&quot;m38.44 41.33c0.0911 1.742 0.7529 3.402 1.734 4.845 0.6616 0.9727 1.803 2.32 1.453 2.985-4.479 8.5 0.6224 7.022 1.083 6.167 3.188-5.917 6.125-4.104 4.647-10.52 0 0 5.27-1.81 5.52-7.977&quot;/&gt;
    &lt;path d=&quot;m48.15 45.59s2.367 3.204 7.758 2.693c0 0-3.326 6.762 0 7.62 1.917 0.4941 4.722-11.16 4.722-11.16s-1.839-0.7937-3.951-4.182&quot;/&gt;
  &lt;/g&gt;
&lt;/svg&gt;
&lt;p&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Emoji designed by OpenMoji – the open-source emoji and icon project. License: CC BY-SA 4.0  This one in particular was designed by Sofie Ascherl: https://openmoji.org/library/emoji-1F408/&lt;/span&gt;&lt;/span&gt;&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Yes, that makes this a copy cat.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;svg viewBox=&quot;0 0 72 72&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;
&amp;lt;g xmlns=&quot;http://www.w3.org/2000/svg&quot; id=&quot;line&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; stroke-miterlimit=&quot;10&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; stroke=&quot;#000&quot;&amp;gt;
    
    &amp;lt;path d=&quot;m12.46 35.74c-2.333 1-4.917 0.8333-4.917 0.8333-1.677 0.1458-3.115-4.01-2.485-4.733l3.318-5.1-1.75-3.417s5.008-1.415 7.883 2.09c0.3444 0.42 0.7943 0.7429 1.279 0.9871 0.0298 0.015 0.0602 0.0302 0.0912 0.0456 2.593 1.289 5.546 1.571 8.385 0.9981 7.222-1.458 14.07-1.37 21.7 2.212 7.625 3.583 14.53-2.25 13.64-7.5-0.793-4.647 3.562-7.583 6.75-5&quot;/&amp;gt;
    &amp;lt;path d=&quot;m16.05 48.82c0.6006-2.206 8.491-3.648 8.491-3.648s3.228-1.201 1.426-4.504&quot;/&amp;gt;
    &amp;lt;path d=&quot;m18.3 33.24c-1.543 1.834-3.893 4.803-0.44 9.158 0 0-6.756 2.853-6.006 8.033 0 0 0.3624 2.476 2.402 2.402&quot;/&amp;gt;
    &amp;lt;path d=&quot;m23.5 50.03c-1.156 7.254 2.386 6.055 3.017 5.661 1.148-0.7173 1.848-9.854 3.952-11.31 1.592-1.104 8.167-0.3021 8.167-0.3021&quot;/&amp;gt;
    &amp;lt;path d=&quot;m38.44 41.33c0.0911 1.742 0.7529 3.402 1.734 4.845 0.6616 0.9727 1.803 2.32 1.453 2.985-4.479 8.5 0.6224 7.022 1.083 6.167 3.188-5.917 6.125-4.104 4.647-10.52 0 0 5.27-1.81 5.52-7.977&quot;/&amp;gt;
    &amp;lt;path d=&quot;m48.15 45.59s2.367 3.204 7.758 2.693c0 0-3.326 6.762 0 7.62 1.917 0.4941 4.722-11.16 4.722-11.16s-1.839-0.7937-3.951-4.182&quot;/&amp;gt;
  &amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You don&amp;rsquo;t need spaces as long as you can tell that numbers or commands are distinct.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can continue adding additional sets of parameters to a command. For example: &lt;code&gt;l&lt;/code&gt; says this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any subsequent coordinate pair(s) are interpreted as parameter(s) for implicit relative LineTo (&lt;code&gt;l&lt;/code&gt;) command(s) (see below).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SVG doesn&amp;rsquo;t do math, so &lt;code&gt;1-2&lt;/code&gt; is two points: &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;-2&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;c&lt;/code&gt; is a cubic bezier curve&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#b%C3%A9zier_curves&quot;&gt;MDN tutorial on Path Cubic Bezier Curves&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cubic Béziers take in two control points for each point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the original, the stroke details: &lt;code&gt;stroke-linecap&lt;/code&gt;, etc., were attributes of each element, we&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks Jeff for pairing with me on this!&lt;/span&gt;&lt;/span&gt; refactored this into the group&amp;rsquo;s attributes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/playing-with-svg</id>
<link href="https://erikarow.land/notes/playing-with-svg" />
<title>Playing with SVG</title>
<updated>2023-08-01T00:00:00+00:00</updated>
<dc:date>2023-08-01T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Mix-Completions&quot;&gt;
&lt;h1&gt;Mix Completions&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve released &lt;a href=&quot;https://hex.pm/packages/mix_completions&quot;&gt;&lt;code&gt;mix_completions&lt;/code&gt;&lt;/a&gt;, a mix task that allows you to add shell completions for &lt;code&gt;mix&lt;/code&gt;. &lt;code&gt;mix_completions&lt;/code&gt; supports completions for &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;zsh&lt;/code&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;fish&lt;/code&gt; already had community contributions adding completions for &lt;code&gt;mix&lt;/code&gt;: &lt;a href=&quot;https://github.com/fish-shell/fish-shell/blob/master/share/completions/mix.fish&quot;&gt;fish completions&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;section id=&quot;How-it-works&quot;&gt;
&lt;h2&gt;How it works&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mix_completions&lt;/code&gt; adds three tasks to work with shell completions:&lt;/p&gt;
&lt;section id=&quot;mix-complete&quot;&gt;
&lt;h3&gt;&lt;code&gt;mix complete&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mix complete&lt;/code&gt; caches the available completions from &lt;code&gt;mix help&lt;/code&gt;. If &lt;code&gt;mix complete&lt;/code&gt; detects a &lt;code&gt;mix.exs&lt;/code&gt; file, it will cache these completions in the project in &lt;code&gt;.mix_complete.cache&lt;/code&gt;. Otherwise it will store the cache in &lt;code&gt;$XDG_CACHE_HOME/.mix_complete.cache&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This means that you can have a separate set of completions for a project with custom tasks than what is generally available to mix globally.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;mix-completebash&quot;&gt;
&lt;h3&gt;&lt;code&gt;mix complete.bash&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mix complete.bash&lt;/code&gt; will refresh the cache a la &lt;code&gt;mix complete&lt;/code&gt;, and outputs bash that when sourced enables shell completions for &lt;code&gt;mix&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;mix-completezsh&quot;&gt;
&lt;h3&gt;&lt;code&gt;mix complete.zsh&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mix complete.zsh&lt;/code&gt;, like its &lt;code&gt;bash&lt;/code&gt; counterpart, refreshes the cache and generates output that can be loaded by &lt;code&gt;zsh&lt;/code&gt;. Instructions on where to put this output can be found in the &lt;a href=&quot;https://github.com/erikareads/mix_completions#zsh-completions&quot;&gt;README&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Why-Cache-Completions&quot;&gt;
&lt;h2&gt;Why Cache Completions&lt;/h2&gt;
&lt;p&gt;With shell completions there seem to be two ways of sourcing the completions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Ask the program for the completions available. This is the approach that &lt;a href=&quot;https://cobra.dev/&quot;&gt;cobra&lt;/a&gt; and &lt;a href=&quot;https://click.palletsprojects.com/en/8.1.x/&quot;&gt;click&lt;/a&gt; take. The shell completions they output are simply a parser for completions output by the program itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Caching completions outside of the program. This is the approach that tools like &lt;a href=&quot;https://github.com/DannyBen/completely&quot;&gt;completely&lt;/a&gt; take. Saving the completions in plain text or directly in the shell output.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I chose to use option 2, because Elixir has a non-trivial startup time. Recently work has reduced the startup time of the BEAM for Elixir, but &lt;code&gt;mix&lt;/code&gt; still takes a few seconds to run on my machine. Instead of waiting multiple seconds for completions to come back, I chose to cache the completions in a TSV that can parsed and handled by the shell completions directly.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Where-to-store-the-cache&quot;&gt;
&lt;h2&gt;Where to store the cache?&lt;/h2&gt;
&lt;p&gt;This project led me to learn about the &lt;a href=&quot;https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html&quot;&gt;XDG Base Directory Specification&lt;/a&gt;. I&amp;rsquo;ve known about these environment variables for a while, but I didn&amp;rsquo;t know how to use them as a software author.&lt;/p&gt;
&lt;p&gt;The XDG specification gives guidance on where to put configuration or cache files on unix systems. The recommendations were simple to use: &lt;code&gt;XDG_CACHE_HOME&lt;/code&gt; is configurable by a user, and defaults to &lt;code&gt;$HOME/.local/cache&lt;/code&gt; if unset.&lt;/p&gt;
&lt;p&gt;I can either put my cache as a file in that directory or create a subdirectory if I have multiple cached things to store. &lt;code&gt;mix_completions&lt;/code&gt; only stores one TSV for its cache, so it&amp;rsquo;s stored directly in the &lt;code&gt;XDG_CACHE_HOME&lt;/code&gt; directory.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Finding-all-the-tasks&quot;&gt;
&lt;h2&gt;Finding all the tasks&lt;/h2&gt;
&lt;p&gt;Initially, when I wanted to find all of the available mix tasks,
I used &lt;code&gt;System.shell&lt;/code&gt; to call &lt;code&gt;mix help&lt;/code&gt; and then processed the output with &lt;code&gt;awk&lt;/code&gt;.
This got the job done, but felt fragile.&lt;/p&gt;
&lt;p&gt;While explaining this to a friend, they pointed out that &lt;code&gt;mix help --names&lt;/code&gt; does this work for me.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks Jeff!&lt;/span&gt;&lt;/span&gt; Though I did have to filter &lt;code&gt;iex&lt;/code&gt; from the list, and I was still invoking &lt;code&gt;System.shell&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then I realized that if &lt;code&gt;mix&lt;/code&gt; had an option for this, it must know how to find (and print) all of the available tasks. Now, &lt;code&gt;mix_completions&lt;/code&gt; uses vendored versions of the same functions that &lt;code&gt;mix help&lt;/code&gt; uses. This proved to be useful when I switched from a simple list of tasks to a tab-separated values file of both tasks and their shortsdocs, since &lt;code&gt;Mix.Task&lt;/code&gt; provides helpers to fetch things like a task&amp;rsquo;s shortdoc.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Limitations&quot;&gt;
&lt;h2&gt;Limitations&lt;/h2&gt;
&lt;p&gt;Since I chose to work in a project agnostic way, I have no way of knowing what arguments and flag are available for subcommands. Thus I chose to only provide completions for available tasks, since I can ask &lt;code&gt;mix&lt;/code&gt; for these directly. The &lt;a href=&quot;https://github.com/fish-shell/fish-shell/blob/master/share/completions/mix.fish&quot;&gt;&lt;code&gt;fish&lt;/code&gt; community completions&lt;/a&gt; provide more granularity, at the cost of pre-assuming which tasks you have available.&lt;/p&gt;
&lt;p&gt;I chose to use caching over hard-coding so that you can detect new tasks and add completions for them, if only at the surface level.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Try-It-Now&quot;&gt;
&lt;h2&gt;Try It Now&lt;/h2&gt;
&lt;p&gt;If you would like to try &lt;code&gt;mix_completions&lt;/code&gt; run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mix archive.install hex mix_completions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instructions on how to source the completions for your chosen shell are in the &lt;a href=&quot;https://github.com/erikareads/mix_completions&quot;&gt;README&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please report any issues you find. :)&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;mix completions example gif&quot; src=&quot;/mix_completions_example.gif&quot;&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/articles/mix-completions</id>
<link href="https://erikarow.land/articles/mix-completions" />
<title>Mix Completions</title>
<updated>2023-07-13T00:00:00+00:00</updated>
<dc:date>2023-07-13T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;zsh-Completion&quot;&gt;
&lt;h1&gt;zsh Completion&lt;/h1&gt;
&lt;p&gt;Today I continued my exploration of shell completion with &lt;a href=&quot;/notes/zsh&quot;&gt;&lt;code&gt;zsh&lt;/code&gt;&lt;/a&gt; completion. 
And it&amp;rsquo;s a lot simpler than &lt;a href=&quot;/notes/bash-completion&quot;&gt;bash completion&lt;/a&gt;.&lt;/p&gt;
&lt;section id=&quot;Enabling-zsh-Completion&quot;&gt;
&lt;h2&gt;Enabling zsh Completion&lt;/h2&gt;
&lt;p&gt;I learned that you can enable &lt;code&gt;zsh&lt;/code&gt; completion to autostart by adding these two lines to your &lt;code&gt;.zshrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zsh&quot;&gt;autoload -Uz compinit
compinit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both were added by the &lt;code&gt;zsh&lt;/code&gt; configuration wizard when I opened the shell for the first time.
The first line loads &lt;code&gt;compinit&lt;/code&gt; so that it&amp;rsquo;s available to &lt;code&gt;zsh&lt;/code&gt;.
The second line calls &lt;code&gt;compinit&lt;/code&gt; to enable completions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;Custom-completion&quot;&gt;
&lt;h2&gt;Custom completion&lt;/h2&gt;
&lt;p&gt;A minimal example of &lt;code&gt;zsh&lt;/code&gt; completion looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zsh&quot;&gt;#compdef my_echo

_my_echo()
{
  completions=(&quot;hello&quot; &quot;hear&quot; &quot;today&quot;)
  _describe &quot;completions&quot; completions
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;rsquo;s it.&lt;/p&gt;
&lt;p&gt;In order to enable this completion, I needed to name the file &lt;code&gt;_my_echo&lt;/code&gt;,
and add it to my &lt;code&gt;zsh&lt;/code&gt; &lt;code&gt;fpath&lt;/code&gt; in my &lt;code&gt;.zshrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zsh&quot;&gt;fpath=(~/.zsh/functions $fpath)
autoload -Uz compinit
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;rsquo;s break down the minimal example:&lt;/p&gt;
&lt;section id=&quot;compdef&quot;&gt;
&lt;h3&gt;&lt;code&gt;#compdef&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;compinit&lt;/code&gt; runs, &lt;code&gt;zsh&lt;/code&gt; will look at the first line of each file it finds on the &lt;code&gt;fpath&lt;/code&gt;.
&lt;code&gt;#compdef&lt;/code&gt; is a tag that defines the function to be called for &lt;code&gt;name&lt;/code&gt;, in our case &lt;code&gt;my_echo&lt;/code&gt;.
Since the filename matches the function name, it loads &lt;code&gt;_my_echo&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;_describe&quot;&gt;
&lt;h3&gt;&lt;code&gt;_describe&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;_describe&lt;/code&gt; is a utility function provided by &lt;code&gt;zsh&lt;/code&gt; that takes a tag, 
in this case &lt;code&gt;&quot;completions&quot;&lt;/code&gt;,
and an array of completions and loads them.&lt;/p&gt;
&lt;p&gt;Unlike &lt;code&gt;bash&lt;/code&gt;, there&amp;rsquo;s no further work needed. &lt;code&gt;zsh&lt;/code&gt; has all the information it needs, and dutifully provides tab completion for &lt;code&gt;my_echo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The simplicity of &lt;code&gt;zsh&lt;/code&gt; after &lt;code&gt;bash&lt;/code&gt; is refreshing.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/zsh-completion</id>
<link href="https://erikarow.land/notes/zsh-completion" />
<title>zsh Completion</title>
<updated>2023-07-03T00:00:00+00:00</updated>
<dc:date>2023-07-03T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Bash-Completion&quot;&gt;
&lt;h1&gt;Bash Completion&lt;/h1&gt;
&lt;p&gt;This week, I&amp;rsquo;ve been exploring how tab completion works in Bash. 
I knew that it was possible to generate bash completions for command line utilities,
but I never knew how it worked.&lt;/p&gt;
&lt;p&gt;So I cracked open the source code for &lt;a href=&quot;https://click.palletsprojects.com/en/8.1.x/&quot;&gt;&lt;code&gt;click&lt;/code&gt;&lt;/a&gt;, a python framework for command line applications that had shell completion as a feature. Helpfully, the shell completions were contained in &lt;a href=&quot;https://github.com/pallets/click/blob/d0af32d8e7d78f4fdaf9c3d1559e1ffaac1b2569/src/click/shell_completion.py#L92&quot;&gt;&lt;code&gt;shell_completion.py&lt;/code&gt;&lt;/a&gt;.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;The way that &lt;code&gt;click&lt;/code&gt; does shell completions is interesting, it uses the application itself to provide completions. I may revisit how this works in the future.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The most helpful line was one that looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;complete -o nosort -F complete_function program_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With both precise &lt;code&gt;completion_function&lt;/code&gt; and &lt;code&gt;program_name&lt;/code&gt; determined by the installation of the &lt;code&gt;click&lt;/code&gt; application.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;complete&lt;/code&gt; is a bash builtin, but &lt;code&gt;help complete&lt;/code&gt; provides little detail as to how it works. In particular, there&amp;rsquo;s no mention of the &lt;code&gt;-F&lt;/code&gt; flag that &lt;code&gt;click&lt;/code&gt; uses.&lt;/p&gt;
&lt;section id=&quot;Info-to-the-Rescue&quot;&gt;
&lt;h2&gt;Info to the Rescue&lt;/h2&gt;
&lt;p&gt;While &lt;code&gt;help&lt;/code&gt; proved to be unhelpful, 
&lt;code&gt;info&lt;/code&gt; a tool I knew about, 
but hadn&amp;rsquo;t previously explored, 
had exactly what I needed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html&quot;&gt;Section 8.6&lt;/a&gt; Programmable Completion and &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html&quot;&gt;Section 8.7&lt;/a&gt; Programmable Completion Builtins proved to share exactly what I wanted to know.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I&amp;rsquo;m linking to the web versions, but this information is available through &lt;code&gt;info bash&lt;/code&gt; on the command line.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s walk through our line of bash from before:&lt;/p&gt;
&lt;section id=&quot;complete-program_name&quot;&gt;
&lt;h3&gt;&lt;code&gt;complete program_name&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;complete&lt;/code&gt; works by registering completions for a particular &lt;code&gt;name&lt;/code&gt;, in most cases this is the builtin or program that we want completions for.
Once those completions are registered, the particular method defined will work every time completion is invoked, typically by the the &lt;code&gt;tab&lt;/code&gt; key.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;-o-nosort&quot;&gt;
&lt;h3&gt;&lt;code&gt;-o nosort&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;-o&lt;/code&gt; sets a &lt;code&gt;comp-option&lt;/code&gt; with specifies extra behavior for &lt;code&gt;complete&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this case, &lt;code&gt;-o nosort&lt;/code&gt; tells &lt;code&gt;complete&lt;/code&gt; not to sort the completions array that it receives.
In this case, it allows &lt;code&gt;click&lt;/code&gt; to precisely control the order of completions that it shows.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;-F-complete_function&quot;&gt;
&lt;h3&gt;&lt;code&gt;-F complete_function&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This is most interesting part of &lt;code&gt;complete&lt;/code&gt;&amp;rsquo;s behavior.
&lt;code&gt;-F&lt;/code&gt; specifies a bash function that will be invoked when completions are asked for on the registered name.&lt;/p&gt;
&lt;p&gt;This function receives three arguments from &lt;code&gt;complete&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$1&lt;/code&gt; is set to the the name of command which is receiving completions.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$2&lt;/code&gt; is set to the word being completed.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$3&lt;/code&gt; is set to the word preceding the word being completed.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;$3&lt;/code&gt; allows for the invoked function to handle nested commands, such as &lt;code&gt;git&lt;/code&gt;&amp;rsquo;s &lt;code&gt;branch&lt;/code&gt; which will complete on available branches for the repo.&lt;/p&gt;
&lt;p&gt;When the function finishes, the completions are retrieved from the value of the &lt;code&gt;COMPREPLY&lt;/code&gt; array variable.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Putting-it-together&quot;&gt;
&lt;h2&gt;Putting it together&lt;/h2&gt;
&lt;p&gt;I now had a mental model of how the completions worked, but I wanted to solidify my knowledge by creating a minimal example.&lt;/p&gt;
&lt;p&gt;My &lt;code&gt;name&lt;/code&gt;d command will be &lt;code&gt;my_echo&lt;/code&gt;, a shell wrapper around &lt;code&gt;echo&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/usr/bin/env bash
echo $1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in mind, I wrote the following bash:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;_my_echo_complete() {
  local options=(&quot;hello&quot; &quot;hear&quot; &quot;world&quot; &quot;today&quot;)
  for option in ${options[*]};
  do
    COMPREPLY+=($(echo &quot;$option&quot; | grep $2));
  done
}

_my_echo_setup() {
  complete -F _my_echo_complete my_echo
}

_my_echo_setup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hadn&amp;rsquo;t worked with bash arrays before, so it took some experimentation to learn about &lt;code&gt;()&lt;/code&gt; to create an array.
Note that the parenthesis are used both for &lt;code&gt;options&lt;/code&gt; and next to the &lt;code&gt;+=&lt;/code&gt; on &lt;code&gt;COMPREPLY&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;[*]&lt;/code&gt; operator inside &lt;code&gt;${options[*]}&lt;/code&gt; unpacks the array so that &lt;code&gt;for&lt;/code&gt; can iterate through it.&lt;/p&gt;
&lt;p&gt;Once I wrote this bash, I added it to a file called &lt;code&gt;complete_function&lt;/code&gt; which I then sourced:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ source complete_function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;bash completion example gif&quot; src=&quot;/bash_completion_example.gif&quot;&gt;&lt;/p&gt;
&lt;p&gt;This version still has issues (hitting tab with no input makes grep throw error once for every item in the array),
but it&amp;rsquo;s a working version of tab completion for a program I &amp;ldquo;wrote&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I look forward to trying to add tab completion in bash to future tools.&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Special thanks to Jeff and Kathrin who joined me in my exploration of Bash completion.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/bash-completion</id>
<link href="https://erikarow.land/notes/bash-completion" />
<title>Bash Completion</title>
<updated>2023-06-26T00:00:00+00:00</updated>
<dc:date>2023-06-26T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;YouTube-RSS-Feeds&quot;&gt;
&lt;h1&gt;YouTube RSS Feeds&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m trying to get back into using RSS feeds.
YouTube used to make it easy to follow channels by RSS,
but they&amp;rsquo;ve removed that ease in favor of what seems to be channeling you into creating a Google account.&lt;/p&gt;
&lt;p&gt;YouTube feeds do still generate an RSS feed though.
It can be found at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://www.youtube.com/feeds/videos.xml?channel_id=&amp;lt;channel_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;&amp;lt;channel_id&amp;gt;&lt;/code&gt; is replaced with the identifier for the YouTube channel you want to follow.
However, YouTube no longer uses these channel ids in the channel URL, 
phasing them out in favor of &lt;code&gt;@&lt;/code&gt; style handles for each channel.
This leads to easier to remember links to channels,
but that &lt;code&gt;@&lt;/code&gt;-handle doesn&amp;rsquo;t work in the feeds link above.&lt;/p&gt;
&lt;p&gt;I found that this channel id was still available under the &amp;ldquo;share&amp;rdquo; arrow on the &amp;ldquo;About&amp;rdquo; page for a channel.&lt;/p&gt;
&lt;p&gt;I was talking to my friend Jeff, and we decided to see if we could do something about this manual process of navigating to the &amp;ldquo;About&amp;rdquo; page and clicking the share arrow.&lt;/p&gt;
&lt;section id=&quot;The-Search-is-On&quot;&gt;
&lt;h2&gt;The Search is On&lt;/h2&gt;
&lt;p&gt;My first thought was to open the browser DevTools on the About page.
Here I used the inspector to find the HTML for the share arrow.
This didn&amp;rsquo;t lead far, as the arrow is powered by javascript. I didn&amp;rsquo;t know how to search the javascript for the HTML class, since javascript is often split up across multiple files.&lt;/p&gt;
&lt;p&gt;After a web search I found a Chrome&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;I usually browse with Firefox, but Jeff was more familiar with the Chrome DevTools. I haven&amp;rsquo;t determined if there is an equivalent &amp;ldquo;search everything&amp;rdquo; for Firefox DevTools.&lt;/span&gt;&lt;/span&gt; DevTools help article: &lt;a href=&quot;https://developer.chrome.com/docs/devtools/search/&quot;&gt;Search: Find text across all loaded resources&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here, I meant to search for the HTML class, but I accidentally pasted the clipboarded channel-id.&lt;/p&gt;
&lt;p&gt;Turns out it was right there in the HTML&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;This is the channel-id for the @charmcli youtube channel.&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;meta itemprop=&quot;identifier&quot; content=&quot;UCTVHQ9GMFYLalQDynyXNTKQ&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;Parsing-HTML&quot;&gt;
&lt;h2&gt;Parsing HTML&lt;/h2&gt;
&lt;p&gt;I wanted to create a script that would take a channel&amp;rsquo;s &lt;code&gt;@&lt;/code&gt;-handle,
and copy the resulting RSS link to my clipboard so I could use it in my RSS reader.&lt;/p&gt;
&lt;p&gt;Fetching the HTML was easy enough:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl https://www.youtube.com/@charmcli/about
&amp;lt;wall of html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I needed a way to select out the channel-id from the HTML tags. Enter &lt;a href=&quot;/notes/pup&quot;&gt;&lt;code&gt;pup&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pup&lt;/code&gt; is a command line HTML parser.
I could pipe the HTML from &lt;code&gt;curl&lt;/code&gt; into &lt;code&gt;pup&lt;/code&gt; to select all meta tags:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl https://www.youtube.com/@charmcli/about \ 
&amp;gt; | pup &#x27;meta&#x27;
&amp;lt;only meta tags&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wanted to then select a specific tag based on a property:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl https://www.youtube.com/@charmcli/about \
&amp;gt; | pup &#x27;meta[itemprop=&quot;identifier&quot;]&#x27;
&amp;lt;meta itemprop=&quot;identifier&quot; content=&quot;UCTVHQ9GMFYLalQDynyXNTKQ&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, &lt;code&gt;pup&lt;/code&gt; provides an &lt;code&gt;attr&lt;/code&gt; function to select from an attribute, in this case &lt;code&gt;content&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl https://www.youtube.com/@charmcli/about \
&amp;gt; | pup &#x27;meta[itemprop=&quot;identifier&quot;] attr{content}&#x27;
UCTVHQ9GMFYLalQDynyXNTKQ
&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;All-together&quot;&gt;
&lt;h2&gt;All together&lt;/h2&gt;
&lt;p&gt;The final script looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;channel_id=$(curl https://www.youtube.com/$1/about | pup &#x27;meta[itemprop=&quot;identifier&quot;] attr{content}&#x27;)
echo -n &quot;https://www.youtube.com/feeds/videos.xml?channel_id=$channel_id&quot; | xclip -selection clipboard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can follow my favorite YouTube channels from my RSS reader!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/youtube-rss-feeds</id>
<link href="https://erikarow.land/notes/youtube-rss-feeds" />
<title>YouTube RSS Feeds</title>
<updated>2023-06-18T00:00:00+00:00</updated>
<dc:date>2023-06-18T00:00:00+00:00</dc:date>
</entry>

<entry>
<content type="html">
&lt;section id=&quot;Does-Go-Have-Enums&quot;&gt;
&lt;h1&gt;Does Go Have Enums?&lt;/h1&gt;
&lt;p&gt;As I continue to explore Go for my new project,
I wondered if there was a way to do Enums in Go.&lt;/p&gt;
&lt;p&gt;Enums are important for the way I write code, 
because I try to avoid overloading identifiers.
That is, I want each identifier to capture as much of its own context as possible.&lt;/p&gt;
&lt;p&gt;Booleans are the worst&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn1&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn1&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Okay, that&amp;rsquo;s not fair &lt;code&gt;nil&lt;/code&gt; or null is also semantically anemic, and provide less information than a boolean. But only slightly.&lt;/span&gt;&lt;/span&gt; for this. 
They are semantically anemic, 
in that if I see one in a code base, 
I have to find what generated it to get context about what it does.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;do_something(&quot;hello&quot;, false)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What does that &lt;code&gt;false&lt;/code&gt; do?
I&amp;rsquo;ll need to look up the function signature of &lt;code&gt;do_something&lt;/code&gt; to find out.&lt;/p&gt;
&lt;p&gt;In Elixir, booleans are a union of two atoms:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type bool :: true | false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I can easily replace the boolean with an &amp;ldquo;enum&amp;rdquo;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type text_state :: :capitalize | :lower_case
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can get a better sense for my function&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn2&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn2&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;&lt;code&gt;do_something&lt;/code&gt; is still a bad name, but at least the arguments are more readable.&lt;/span&gt;&lt;/span&gt; from before:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;do_something(&quot;hello&quot;, :capitalize)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I lose the ability to easily use conditionals&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn3&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn3&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Elixir lets me pattern match, which means that I can avoid conditionals in a lot of places where, say, python would require them.&lt;/span&gt;&lt;/span&gt;, 
but I gain significant readability in my functions, 
even at the call site.&lt;/p&gt;
&lt;section id=&quot;Go-Enums&quot;&gt;
&lt;h2&gt;Go Enums&lt;/h2&gt;
&lt;p&gt;Go &lt;strong&gt;does&lt;/strong&gt; have Enums&lt;label class=&quot;margin-toggle sidenote-number&quot; for=&quot;fn4&quot;&gt;&lt;/label&gt;&lt;input class=&quot;margin-toggle&quot; id=&quot;fn4&quot; type=&quot;checkbox&quot;&gt;&lt;span class=&quot;note-right note sidenote&quot;&gt;&lt;span class=&quot;footnote-p&quot;&gt;Thanks to &lt;a href=&quot;https://www.sohamkamani.com/golang/enums/&quot;&gt;this&lt;/a&gt; awesome guide for an introduction to Go enums.&lt;/span&gt;&lt;/span&gt;, though they behave a bit differently than Elixir&amp;rsquo;s &amp;ldquo;alternative atoms for matching&amp;rdquo; approach.&lt;/p&gt;
&lt;p&gt;They look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type TextState int64

const (
	Capitalize TextState = iota
	LowerCase
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go Enums are simply constants that are statically newtyped so they only type to themselves.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://go.dev/ref/spec#Iota&quot;&gt;&lt;code&gt;iota&lt;/code&gt;&lt;/a&gt; auto-increments an untyped integer so that you don&amp;rsquo;t have to specify a value for each element of the constant.&lt;/p&gt;
&lt;p&gt;It was weird to me that Enums in Go tend to be backed by integers,
but since Go is statically typed, 
you get strong guarantees that your value is &lt;code&gt;Capitalize&lt;/code&gt; and not &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I look forward to using Go Enums to decrease the likelihood of bugs in my code.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;

</content>
<id>https://erikarow.land/notes/go-enums</id>
<link href="https://erikarow.land/notes/go-enums" />
<title>Does Go Have Enums?</title>
<updated>2023-06-18T00:00:00+00:00</updated>
<dc:date>2023-06-18T00:00:00+00:00</dc:date>
</entry>

<dc:date>2024-07-27T00:00:00+00:00</dc:date>
</feed>