<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Reasonable Performance</title>
    <link>https://vfoley.xyz/</link>
    <description>Recent content on Reasonable Performance</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 07 Apr 2024 00:00:00 +0000</lastBuildDate>
    
        <atom:link href="https://vfoley.xyz/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Insights and understanding — AI won&#39;t take your job</title>
      <link>https://vfoley.xyz/insights/</link>
      <pubDate>Sun, 07 Apr 2024 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/insights/</guid>
      <description>&lt;p&gt;When I last visited my parents, my mom and dad asked me whether I was worried about ChatGPT or other AI systems taking away programmers&amp;rsquo; jobs and whether I was worried about my own future.
My answer to them—and this might be a naïve take—is that I&amp;rsquo;m not very worried and that I think that programmers are going to be around for a while yet.&lt;/p&gt;
&lt;p&gt;The reason I think this is because the current breed of AIs that make headlines are &lt;em&gt;generative&lt;/em&gt; AIs, i.e., AIs that are able to produce text, images, songs, videos, etc.
Importantly, those AIs do not understand what they output.
Generative AIs are really good at stringing together words and symbols in an order that makes them &lt;em&gt;look&lt;/em&gt; intelligent, but it&amp;rsquo;s just a very impressive illusion; they don&amp;rsquo;t have the capacity to do real analysis.&lt;/p&gt;
&lt;p&gt;Programmers, contrary to the common perception, don&amp;rsquo;t just spend all day writing code at a keyboard without thought.
The important part of our job is the time we spend understanding a problem.
We use our ability to recognize patterns, to notice oddities, to question the status quo, to wonder &amp;ldquo;what if&amp;rdquo; to augment our understanding of a problem and of its solution space.
This ability to take fragments of information—code, data, timings, test programs, colleagues, documentation, dashboards, etc.—, to establish links between them, and to derive new knowledge, that to me is &lt;em&gt;real intelligence&lt;/em&gt;, and as far as I know, it&amp;rsquo;s still only a human thing.&lt;/p&gt;
&lt;p&gt;The recent &lt;a href=&#34;https://en.wikipedia.org/wiki/XZ_Utils_backdoor&#34;&gt;xz backdoor&lt;/a&gt; provides a good example of this.
Andres Freund noticed that his OpenSSH daemon was taking more CPU than usual and that SSH connections were taking longer than usual.
His initial observation and subsequent digging unveiled an extremely sophisticated attack that could&amp;rsquo;ve created a huge cybersecurity nightmare.
GitHub CoPilot might be good at auto-completing the stanza for opening a file in Java, but unless it got an impressive upgrade in recent days, it cannot notice a slow SSH connection, use debugging tools to find the the source of the CPU usage, notice that the slowdown comes from an suspicious unnamed symbol in a compression library, decipher the complex dance for creating the backdoor, and reporting its findings to the community.&lt;/p&gt;
&lt;p&gt;Obviously, the day-to-day of most programmers doesn&amp;rsquo;t involve finding hidden backdoors, nevertheless, this ability to understand a problem, to investigate, to derive insights is primordial for doing our jobs.
Generative AIs are not going to replace programmers; they might become a useful addition to our toolbox, but when the dust has settled, their usage will certainly be more modest than the current hype predicts.&lt;/p&gt;
&lt;aside&gt;
Here are some ways to gain understanding and insights:
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inspect your data regularly:&lt;/strong&gt; programs transform data, so make sure you know how to look at your data and how to &amp;ldquo;ask it questions&amp;rdquo;; whether it&amp;rsquo;s with SQL queries, awk scripts, or jq filters, being able to slice-and-dice data is a good way to find places where improvements can be made. Make sure you are given access to servers, dashboards, cloud consoles, etc. that you&amp;rsquo;ll need.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Revisit your code:&lt;/strong&gt; how you think your program performs a task and how the program actually does the task might drift as people maintain the code. Revisiting sub-systems once in a while is a good way to see if they&amp;rsquo;ve changed and also, it might be only the third read that a spark of insight strikes you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Talk to your colleagues:&lt;/strong&gt; if something looks weird in the code and you can&amp;rsquo;t figure out why, asking a question like &amp;ldquo;does anybody remember why we do &lt;em&gt;x&lt;/em&gt; in module &lt;em&gt;foo&lt;/em&gt;?&amp;rdquo; is a good way to start a conversation, understand contraints or concerns that aren&amp;rsquo;t evident from the code (aside: there&amp;rsquo;s no such thing as &amp;ldquo;self-documenting code&amp;rdquo;), and might cause the team to revisit previous assumptions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Trust, but verify:&lt;/strong&gt; it&amp;rsquo;s common for a piece of incorrect knowledge to spread among a team and for everyone to accept it and not verify it. When someone says &amp;ldquo;we can&amp;rsquo;t do &lt;em&gt;x&lt;/em&gt; because &lt;em&gt;y&lt;/em&gt; and &lt;em&gt;z&lt;/em&gt;&amp;rdquo;, it&amp;rsquo;s useful to verify. It might have been true in the past, but it might no longer be; it might have never been true in the past, but someone misread the documentation and came away with the wrong conclusion. Verify.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/aside&gt;
</description>
    </item>
    
    <item>
      <title>Simple Precedence</title>
      <link>https://vfoley.xyz/simple-precedence/</link>
      <pubDate>Sun, 04 Feb 2024 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/simple-precedence/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://youtu.be/fIPO4G42wYE&#34;&gt;A discussion&lt;/a&gt; between Jonathan Blow and Casey Muratori on the handling of precedence in Jon&amp;rsquo;s compiler recently popped in my YouTube feed.
The discussion is three hours long and focuses on implementing operator precedence more easily and more simply in Jai using &lt;a href=&#34;https://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/&#34;&gt;Pratt parsing&lt;/a&gt;.
Jon and Casey also talk about the previous implementation of operator precedence in Jai which used tree-rewriting and the classic approach which organizes the different precedence levels into different production rules.&lt;/p&gt;
&lt;p&gt;My favorite approach to operator precedence is the one used in APL, J, and K: &lt;a href=&#34;https://code.kx.com/q4m3/4_Operators/#41-operator-precedence&#34;&gt;get rid of it&lt;/a&gt;.
Array languages are known for their symbol-heavy programs, but something rarely mentioned is that in languages with so many esoteric operators, the rules for reading those operators are the simplest and most straight-forward of all:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All operators have the same precedence, no exception.&lt;/li&gt;
&lt;li&gt;All operators associate to the right, no exception.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With these two rules, it&amp;rsquo;s easy to understand a complex expression: we read right-to-left. Take the following snippet of code (written completely randomly):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;5 | 1 &amp;lt;&amp;lt; 3 &amp;amp; 3 | 1 &amp;lt;&amp;lt; 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In a language like Python or C, do you know what this expression evalutes to without running it or referring to the documentation?
In a language with only the two precedence rules above, it&amp;rsquo;s very easy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;&amp;lt; 4 = 16&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3 | 16 = 19&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3 &amp;amp; 19 = 3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1 &amp;lt;&amp;lt; 3 = 8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;5 | 8 = 13&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having only two simple rules makes it easy for readers of programs to understand complex expressions.
The simple rules also make the life of the language implementors easier: instead of deciding whether to use Pratt Parsing or multi-leveled productions, and deciding on whether &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; should have a higher or lower precedence than &lt;code&gt;&amp;amp;&lt;/code&gt;, the parsing of operators becomes something that doesn&amp;rsquo;t require a three hour discussion.&lt;/p&gt;
&lt;p&gt;The one thing that is lost by going for this radically simpler operator precedence is familiarity.
We&amp;rsquo;ve had PEDMAS drilled into our skulls since junior high; remembering PEDMAS is extremely important for those quizzes on Twitter claming that &amp;ldquo;only 1% of the population gets this question right&amp;rdquo;.
But if we are willing to give up familiarity for a little while—I say for a little while, because eventually the no-precedence approach becomes second nature—we can have a language that&amp;rsquo;s simpler to understand and simpler to implement.&lt;/p&gt;
&lt;p&gt;Unfortunately, this kind of radical simplicity is rarely seen because programmers don&amp;rsquo;t value simplicity very much and don&amp;rsquo;t mind the extra complexity of things like precedence rules—they even &lt;em&gt;like&lt;/em&gt; extra, unnecessary complexity.
But that&amp;rsquo;ll be the subject of another post&amp;hellip;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My Impressions of Hare</title>
      <link>https://vfoley.xyz/hare/</link>
      <pubDate>Wed, 24 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/hare/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://harelang.org/blog/2022-04-25-announcing-hare/&#34;&gt;When Hare was announced&lt;/a&gt; back in 2022, I saw the post on Hacker News, went to the website, looked at the documentation, and my reaction was a lukewarm &amp;ldquo;meh&amp;rdquo;.
Hare was a new entry in what I call the &amp;ldquo;Modern Cs&amp;rdquo;: languages that use C as their base inspiration and try to improve upon C by adding new features, removing some footguns, and polishing some sharp corners.
These languages also try to avoid the complexity and &lt;a href=&#34;https://github.com/zakirullin/cognitive-load/blob/main/README.md#feature-rich-languages&#34;&gt;cognitive load&lt;/a&gt; of C++, Ada, or Rust by omitting certain features (e.g., exceptions, RAII).
The Modern Cs include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zig:&lt;/strong&gt; Probably the best-known Modern C, its main claim to fame is &lt;code&gt;comptime&lt;/code&gt;, the ability to run Zig code at compile-time.
This one feature is used pervasively in the language and it subsumes many features of other language: for example, a generic data structure can be implemented by calling a comptime function which accepts a type and returns a struct where the input type has been filled in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Odin:&lt;/strong&gt; Another well-known Modern C, Odin is a simpler language than Zig and it draws its inspiration from C, but also Pascal and Go. One cool feature of Odin is its implicit context argument which allows custom loggers or memory allocators to be passed around without being explicitly in a function&amp;rsquo;s parameters&amp;rsquo; list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;C3:&lt;/strong&gt; A language that attempts to stay closer to C than the others, it still manages to improve upon C with better error handling, modules, generics, and cleaner semantics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Jai:&lt;/strong&gt; Jonathan Blow&amp;rsquo;s language which is currently in private beta. Like Zig, the big idea of Jai is to allow any part of a program to be run at compile-time by prefixing a statement with &lt;code&gt;#run&lt;/code&gt;. The language is currently used for the creation of a AAA game, but no one knows when it&amp;rsquo;ll be available to the general public.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my first quick look at the documentation of Hare, I saw a language that clearly improved upon C: it had better error handling, a stronger type system, bound-checked slices, &lt;code&gt;defer&lt;/code&gt; for resource cleanup, UTF-8 support, and fewer syntactic gotchas than C (e.g., no fallthrough in switches, more intuitive declaration syntax).
Hare doesn&amp;rsquo;t have generics, macros, or any means of doing compile-time programming, which was what cooled my interest for the language.
Also, unlike the other languages on this list, Hare uses QBE for its backend instead of LLVM which can raise questions about how fast the generated programs are.
At the time, I thought Hare was cute, but not a language I was interested in or a language that I thought I &lt;em&gt;could&lt;/em&gt; be interested in.&lt;/p&gt;
&lt;p&gt;Fast-forward a couple years, and I hear Drew DeVault, Hare&amp;rsquo;s creator, on the podcast &lt;a href=&#34;https://www.youtube.com/watch?v=42y2Q9io3Xs&#34;&gt;Developer Voices&lt;/a&gt; talking about Hare.
I liked what Drew had to say, many of his sensibilities about programming languages matched my own, and since I had a week off for Christmas and New Year, I figured that I should give the language a try.
When I tried Hare, something unexpected happened: I liked it more than I expected!
The language is more basic than the other Modern Cs and boasts fewer of the features I look for in a language, yet I found that it was the one that most quickly and most comfortably &amp;ldquo;fit my hand&amp;rdquo;.
I learned the basics of the language in a couple of hours and the built-in &lt;code&gt;haredoc&lt;/code&gt; command let me explore the standard library from the comfort of my terminal.
Before long, I could write small programs in Hare without consulting the documentation at every line.
The more I used Hare, the more I realized that I had previously judged it as just a list of features; now that I was actually using it, the holistic experience was better than a simple reading of the features led me to believe.&lt;/p&gt;
&lt;p&gt;Some of my readers may know that I used to be quite a fan of very high-level programming languages, of functional programming, of advanced type system features, etc.
However, over the past few years, age has made me become more conservative in my programming language preferences—I now value simplicity more than I did before and I find myself scowling at some of the advanced modern programming features, grumbling that they exist to solve uncommon problems or, worse, to provide an exciting toy to otherwise bored programmers.
Were I 5–10 years younger, I would totally blow off Hare, but now I value different things in the software that I use and build, Hare appeals to me a lot more.&lt;/p&gt;
&lt;p&gt;One aspect of Hare that I will follow with interest is its evolving story toward safety.
Hare is already a lot safer than C: the compiler inserts bound check for array and slice accesses, the compiler refuses to compile code which doesn&amp;rsquo;t handle error conditions, strings don&amp;rsquo;t have the ambiguity of C where you don&amp;rsquo;t know if &lt;code&gt;length&lt;/code&gt; includes the terminating NUL byte or not, etc.
A lot of the common C footguns are nullified.
However, the language does not track ownership and lifetimes—the programmer must have that discipline—which opens Hare programs to use-after-free and double-free bugs.
There are early discussions of using linear types to prevent those kinds of errors; time will tell whether the Hare developers are able to integrate them in the language without sacrificing the simplicity and &amp;ldquo;feel&amp;rdquo; of the language.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll finish by repeating how pleasantly surprised I was by Hare.
If you value simplicity, directness, and performance, I recommend you give it a go for few hours; I think you&amp;rsquo;ll also be pleasantly surprised.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Tyranny of Existing Code</title>
      <link>https://vfoley.xyz/tyranny-of-existing-code/</link>
      <pubDate>Sun, 12 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/tyranny-of-existing-code/</guid>
      <description>&lt;p&gt;Most programmers have experienced that feeling of worthlessness and powerlessness when we are trying to implement what should be a simple change, but the existing code base resists our attempts.
Worse, often we can see what is causing us to be blocked, yet we cannot bring ourselves to bring down those barriers.
I call this &lt;em&gt;the tyranny of existing code&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In a young software project, one with little infrastructure in place, it&amp;rsquo;s usually straightforward to make changes.
However in a project that&amp;rsquo;s older, one where other programmers have put in place structures to make the codebase &amp;ldquo;clean&amp;rdquo;, &amp;ldquo;maintainable&amp;rdquo;, or &amp;ldquo;extensible&amp;rdquo;, it&amp;rsquo;s often much harder to make changes.
Often, the structures that have been put there &amp;ldquo;to make changes easier&amp;rdquo; or &amp;ldquo;to make it harder to shoot yourself in the foot&amp;rdquo; are the very ones that block us.&lt;/p&gt;
&lt;p&gt;And it is the tyranny of existing code that will prevent us—at least initially—from taking the steps needed to unblock ourselves.
We reason that if there are restrictions in place, &amp;ldquo;they must be there for a reason&amp;rdquo;.
We think about the time that the the original author must have spent to design and implement those structures and we don&amp;rsquo;t want to insult them by deleting their code.
We certainly don&amp;rsquo;t want to put ourselves in a position where we think we know more than them, only to be shown to be wrong.
We show deference to the existing structure by trying to work within its constraints and limitations, even as it impedes our ability to solve the problem.
We day dream of ripping out all that shitty code and replacing it with our own and how much better it would all be; but we quickly return to reality, continue grinding at the problem, and continue finding new ways in which the current code blocks us.
And so we waste hours, days, even weeks, letting the existing code make our lives miserable.&lt;/p&gt;
&lt;p&gt;For example, suppose that the web framework of our application hides the HTTP headers behind a dictionary-like abstraction and only provides the ability to get a specific header.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;impl&lt;/span&gt; HttpRequest {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_header&lt;/span&gt;(header_name: &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;str&lt;/span&gt;) -&amp;gt; Option&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;str&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we were tasked with logging all the headers of incoming requests, how would we do it?
The current interface is clearly insufficient—we need access to all the headers—but what can we do?
We might think about replacing the framework for one that does not hide the headers, but that suggestion sounds ludicrous and risky and will make us sound naïve and unprofessional.
So we start looking for ways to work within the framework.
Maybe there&amp;rsquo;s a new version that exposes the headers?
Maybe there&amp;rsquo;s a middleware system that let us access the raw request?
There&amp;rsquo;s probably, definitely a reason why the original author didn&amp;rsquo;t want us to have access to all the headers—we don&amp;rsquo;t know what kind of problems they have saved us from by not giving us access to all the headers and we should be thankful; really, it&amp;rsquo;s our task that&amp;rsquo;s the problem!&lt;/p&gt;
&lt;p&gt;In time, we find a solution, make our change, and we feel good about ourselves; we overcame the difficulties, our manager congratulated us at the stand-up, and we didn&amp;rsquo;t need to throw a bunch of existing code in the garbage.
We might feel a bit bad about the time and effort it took us and about the extra complexity we introduced though; but it&amp;rsquo;s better to have made the change than to have re-written the whole thing, right?&lt;/p&gt;
&lt;p&gt;But what will happen next time?
Are we going to leave the structures in even as they become more and more inappropriate for the kinds of changes we need to make?
Are we going to live with them even as they make further changes more difficult and the complexity of the project continues to increase?&lt;/p&gt;
&lt;p&gt;The tyranny of existing code suggests that yes, we will.
Code does not have mass, but it has a gravitational pull.
The larger and more complex the code, the more energy is required to escape it: more code to understand, more code to replace, more managers to convince, more programmers to get on board, etc.
Eventually, the code that only needed to handle simple HTTP requests has become so complex because of the web framework and the extra layers of complexity that we added that simple changes require weeks of work and no one dares suggest that the problem is the web framework and that it needs to be replaced.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A skill programmers lack: practice</title>
      <link>https://vfoley.xyz/practice/</link>
      <pubDate>Sat, 10 Dec 2022 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/practice/</guid>
      <description>&lt;p&gt;In the talk &lt;a href=&#34;https://youtu.be/4B00hV3wmMY&#34;&gt;Solving the Right Problems for Engine Programmers&lt;/a&gt;, Mike Acton spends a section of his talk on what he considers the three fundamental areas in which most programmers are incompetent: practice, reasonable defaults, problem solving skills.
The first one in particular is quite interesting, because it enables the two others: someone who practices the craft of programming regularly will develop reasonable defaults and problem solving skills.
Acton says that practicing is an activity that we do individually and where we try to fill in gaps in our knowledge and that as professional, it&amp;rsquo;s our responsibility and obligation to practice.&lt;/p&gt;
&lt;p&gt;But practicing is not a thing that most programmers do.
Mostly, we get thrown into a problem, we read just enough documentation to allow us to complete our work before we&amp;rsquo;re shuttled to the next project with a looming deadline.
It&amp;rsquo;s hard to imagine that we can acquire and build a solid foundation that way.
And it&amp;rsquo;s not the way it happens in other professions: professional sport athletes are expected to practice multiple times a week to maintain their skill levels and improve their areas of weakness; musicians practice their pieces for many days/weeks before their public concerts; astronauts spend years preparing for their missions, they don&amp;rsquo;t just try and wing it.&lt;/p&gt;
&lt;p&gt;Since I saw this video, I&amp;rsquo;ve been trying to make time every week to practice the skills of my profession.
For example, over the last 2–3 weeks, I&amp;rsquo;ve blocked 30 minutes every other day to implement and re-implement sorting algorithms (bubble, insertion, selection, quick, merge, and radix) in multiple languages.
The goals are to solidify my knowledge of the general strategy of those algorithms, understand the different invariants that need to hold (it&amp;rsquo;s very easy to get into an infinite loop because we accidentally use &lt;code&gt;&amp;lt;=&lt;/code&gt; instead of &lt;code&gt;&amp;lt;&lt;/code&gt;), and correctly implementat the algorithms in different languages.
When I started, I had forgotten most of what I knew about sorting algorithms and I spent most of the 30 minutes fumbling about; but with regular practice, I&amp;rsquo;m now able to write all 6 algorithms and their tests in about 20 minutes.
More importantly, I can explain how they work and what invariants need to hold.
Next, I will try and include shell sort and heap sort to the list of sorting algorithms that I understand and can implement.&lt;/p&gt;
&lt;p&gt;My suggestion for people who want to improve as programmers is to try to have a practice routine.
Block time in your schedule a few times a week—not a lot, 30 minutes is plenty—and focus on an area that you want to improve.
It can be data structures and algorithms, creating and running Docker containers, making SQL queries, etc.—whatever you feel that you need to improve.
Then open a blank file and try to get as far as you can.
After the 30 minutes are done, stop, wherever you are.
Let your brain sleep on what you did for a day or two before going back.
The next time you practice, &lt;strong&gt;do not open the previous day&amp;rsquo;s file&lt;/strong&gt;: create another new one and start from scratch again; this is &lt;strong&gt;not&lt;/strong&gt; a project, this is practice.
You are trying to become good enough at a skill that it just flows out of your fingers; saying &amp;ldquo;I accomplished the thing&amp;rdquo; is not enough, you need to aim for &amp;ldquo;I can accomplish the thing quickly and consistently.&amp;rdquo;
After a few sessions, you&amp;rsquo;ll see that you are better at finishing your task in the allotted time.
Then start spacing it out (you can have a daily practice for another topic): practice the same thing a week later, then a month later, three months later, etc.
This is to make sure that the knowledge that you struggled to acquire remains in your mind.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tech companies making parental controls useless</title>
      <link>https://vfoley.xyz/useless-parental-controls/</link>
      <pubDate>Sun, 13 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/useless-parental-controls/</guid>
      <description>&lt;p&gt;How hard is it to get Minecraft for a game console?
If you&amp;rsquo;re an adult you drive to your favorite video game store, buy Minecraft, pop the cartridge in the console, and play.
If you&amp;rsquo;re a kid, your experience is similar, it has one extra step: you nag your parents for a while to get the game, they drive to the store, buy it, you pop the cartridge in the console, and play.
Easy.&lt;/p&gt;
&lt;p&gt;What about getting Minecraft for the PC (Java Edition), how hard is that?
If you are an adult, the process is pretty straight-forward: login with your Microsoft account, click the &amp;ldquo;Buy now&amp;rdquo; button, pay for the game, download and install.
However, if you are a parent trying to buy the PC version of Minecraft for a kid, the process is much more frustrating.
It looks okay from the outside, but thanks to bugs in the implementation, you have basically no choice but to lie and pretend that your kid is 18 years old and opt-out of all the parental controls in order to work around a product that doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;The problem stems from this: the PC version of Minecraft needs to be downloaded &lt;em&gt;while connected with the Microsoft account that will play the game&lt;/em&gt;.
There are many problems with that.&lt;/p&gt;
&lt;p&gt;First, why should I even need a Microsoft account to download the game?
Why not just allow me to pay for the game and download the installer anonymously?
There&amp;rsquo;s a single player mode after all, why is internet connectivity even required?&lt;/p&gt;
&lt;p&gt;Second problem: to create an account for Microsoft, you need to have your own email address.
Kids typically don&amp;rsquo;t have email addresses, and their parents are reluctant to give them one.
But if parent and kid want to play Minecraft together, they &lt;strong&gt;need&lt;/strong&gt; to have two different emails: you can&amp;rsquo;t have multiple profiles under the same email.
And let me tell you, email providers don&amp;rsquo;t make it easy to get an email for kids.
When I tried to get a Gmail for my son, all the parental consent stuff was convoluted and buggy and in the end I threw in the towel and just lied about his age so that we&amp;rsquo;d avoid those difficulties.&lt;/p&gt;
&lt;p&gt;Same deal with Microsoft: if you want to get a Microsoft Account for a child under 13, you need to link it to a parent&amp;rsquo;s account.
That worked fine for me since I already had one, but that would be a lot of extra friction for parents who don&amp;rsquo;t.
Then, the purchase process actually looked okay: my son clicks &amp;ldquo;Buy now&amp;rdquo; in his account and that tells him &amp;ldquo;we&amp;rsquo;re sending an email to your parents for their consent&amp;rdquo;.
In my inbox, I had an email with a big, blue button saying &amp;ldquo;Allow&amp;rdquo;.
That button took me to a page to make the purchase on behalf of your child: that looks sensible and promising.
But alas, there&amp;rsquo;s a bug in the form: I had to enter my address (why? My address in PayPal isn&amp;rsquo;t good enough?) and the form would not allow me to change the country.
For some reason, it was locked under U.S. for me.
Both my profile and my son&amp;rsquo;s clearly say &amp;ldquo;Canada&amp;rdquo; in country of residence.&lt;/p&gt;
&lt;p&gt;And so after an hour of extremely frustrating bullshit, I gave up.
I went in the parental settings, said that my son is allowed to buy whatever he wants without my consent and linked my PayPal account to his profile.&lt;/p&gt;
&lt;p&gt;The process for getting the PC version should be exactly the same as getting a console cartridge.
Kid nags their parents, the parents comes to the PC, click the &amp;ldquo;Buy now&amp;rdquo; link (no logins required), download the installer, and start the game.
Instead, Microsoft opted to have a process that is more complicated and we can see that it&amp;rsquo;s more complicated, because it doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll close with this quote from gaben:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Piracy is almost always a service problem and not a pricing problem&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>You already know how to parse by hand</title>
      <link>https://vfoley.xyz/parsing/</link>
      <pubDate>Mon, 31 Oct 2022 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/parsing/</guid>
      <description>&lt;p&gt;An article was published in /r/rust a couple weeks ago, &lt;a href=&#34;https://naiveai.hashnode.dev/practical-parsing-nom&#34;&gt;Parsing With Nom&lt;/a&gt;, a blog post explaining how to use nom to create a parser for a data format in the BitTorrent protocol called Bencode.
Nom is a Rust library that provides &lt;em&gt;parser combinators&lt;/em&gt;, small functions that provide simple parsing capabilities and which can be combined together to form functions that can parse more complex input.&lt;/p&gt;
&lt;p&gt;The article praises nom for being an easy way to write parsers for people who don&amp;rsquo;t have a CS degree and who haven&amp;rsquo;t dedicated the time and effort needed to read the 200 pages of parsing material in the Dragon Book.
That characterization of parsing saddened me; parsers are super useful, they should be part of every programmer&amp;rsquo;s toolbox, and it&amp;rsquo;s a shame that their reputation as being hard discourages programmers from learning to write them.
It&amp;rsquo;s especially sad, since writing a parser requires only basic programming concepts: functions, loops, ifs, arrays, structs, and recursion.&lt;/p&gt;
&lt;p&gt;Parsing &lt;em&gt;appears&lt;/em&gt; difficult because there are indeed 200 pages of dense theoretical concepts in the Dragon Book.
Academics don&amp;rsquo;t make it appear any easier: to sound authoritative and learned, they use technical terms, like LR(1), LL(k), ε-closures, start sets, shift-reduce conflicts, etc. further reinforcing the impression that parsing is a complex matter better left to people who have the proper training.&lt;/p&gt;
&lt;p&gt;Fortunately, most of what a working programmer who wants to convert text to an in-memory data structure is learned in &lt;em&gt;Programming for Dummies&lt;/em&gt;.
To support this claim, I will demonstrate writing a parser for the Bencode format—the same one as in the nom article—using only programming constructs that you are already familiar with.
By the end of this article, you will find that there is nothing especially hard, technical, or scary about writing parsers and you&amp;rsquo;ll know how to create one yourself.&lt;/p&gt;
&lt;h2 id=&#34;the-data-types&#34;&gt;The data types&lt;/h2&gt;
&lt;p&gt;A parser needs two main pieces of information: the data to be parsed (bytes or tokens) and the position of the current piece of data to be analyzed.
For Bencode, I start with a struct containing two fields: a vector of bytes and an index in that vector.
If more data needed to be tracked, such as line numbers, column numbers, list of errors, etc., the &lt;code&gt;Parser&lt;/code&gt; struct would be a good place to store them, but for this simple parser, we won&amp;rsquo;t bother with other information.&lt;/p&gt;
&lt;aside&gt;
Bencode is simple enough that we can go straight from the raw bytes to an in-memory representation.
For more complex languages, such as JSON or Go, we&#39;d have a _tokenization_ phase that turns chunks of bytes into tokens to make the parsing phase easier.
Tokenization works almost exactly like parsing, except that recursion is disallowed.
&lt;/aside&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;pub struct Parser {
    buf: Vec&amp;lt;u8&amp;gt;,
    pos: usize,
}

impl Parser {
    pub fn new(buf: Vec&amp;lt;u8&amp;gt;) -&amp;gt; Parser {
        Parser { buf, pos: 0 }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We also need a data structure that will be returned by the parsing methods.
In the literature, this is called an abstract syntax tree—an AST.
In Rust, it&amp;rsquo;s typical to use an enum to represent an AST.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BValue {
    Int(i64),
    Str(String),
    List(Vec&amp;lt;BValue&amp;gt;),
    Dict(Vec&amp;lt;(String, BValue)&amp;gt;),
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice how our AST has cases for each of the Bencode value types: integers, strings, lists, and dictionaries.
That&amp;rsquo;s typical: we want the AST to closely mirror specification.&lt;/p&gt;
&lt;p&gt;Finally, we need a type for reporting errors.
Since this is a simple parser, we&amp;rsquo;ll use &lt;code&gt;String&lt;/code&gt; as our error type.
A more involved parser would likely use an enum to explicitly list the different kinds of parsing errors that can occur.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type Error = String;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;utility-methods&#34;&gt;Utility methods&lt;/h2&gt;
&lt;p&gt;Next, we add a few utility methods to our parser.
There are typically two kinds of methods in a parser: parsing methods which know how to parse a small part of the language—we&amp;rsquo;ll start writing those in the next section—and utility methods which are used by the parsing methods.
Here are the four utility methods we&amp;rsquo;ll use.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;peek()&lt;/code&gt;: this returns the byte at &lt;code&gt;buf[pos]&lt;/code&gt;; if &lt;code&gt;pos&lt;/code&gt; is past the end of the buffer, we return the byte &lt;code&gt;0&lt;/code&gt;. For some kinds of parsers, especially binary parsers, &lt;code&gt;0&lt;/code&gt; could be a valid byte, and so another approach should be used to represent EOF—&lt;code&gt;Option&amp;lt;u8&amp;gt;&lt;/code&gt; would be one such choice.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;advance()&lt;/code&gt;: this is like &lt;code&gt;peek()&lt;/code&gt;, and it also moves &lt;code&gt;pos&lt;/code&gt; forward by one.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expect(b)&lt;/code&gt;: this method calls &lt;code&gt;advance()&lt;/code&gt; and verifies that the byte &lt;code&gt;b&lt;/code&gt; was consumed; if any other byte was seen, it returns an error.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eof()&lt;/code&gt;: this returns true if all the input buffer has been consumed and false otherwise. It&amp;rsquo;s not completely necessary since we can get the functionality with &lt;code&gt;peek() == 0&lt;/code&gt;, but it makes the source code easier to read.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(A parser for a more complex language would have more utility methods, such as &lt;code&gt;skip_spaces()&lt;/code&gt; or &lt;code&gt;report_error()&lt;/code&gt; to avoid some tedium, but I&amp;rsquo;d expect to find our four methods in all parsers.)&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;impl Parser {
    fn peek(&amp;amp;self) -&amp;gt; u8 {
        if self.pos &amp;gt;= self.buf.len() {
            return 0;
        } else {
            return self.buf[self.pos];
        }
    }

    fn advance(&amp;amp;mut self) -&amp;gt; u8 {
        let b = self.peek();
        if b != 0 {
            self.pos += 1;
        }
        return b;
    }

    fn expect(&amp;amp;mut self, expected: u8) -&amp;gt; Result&amp;lt;(), Error&amp;gt; {
        let actual = self.advance();
        if actual != expected {
            return Err(format!(
                &amp;#34;syntax error: expected {:?}, found {:?}&amp;#34;,
                expected as char, actual as char
            ));
        }
        return Ok(());
    }

    fn eof(&amp;amp;self) -&amp;gt; bool {
        return self.peek() == 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And that&amp;rsquo;s it, we have all the building blocks needed to write our parser.
The rest of the parser will be built on top of these utility methods and will use the programming constructs that you&amp;rsquo;ve been familiar with since you started programming.&lt;/p&gt;
&lt;h2 id=&#34;the-parsing-functions&#34;&gt;The parsing functions&lt;/h2&gt;
&lt;h3 id=&#34;predicting-the-kind-of-data-to-read&#34;&gt;Predicting the kind of data to read&lt;/h3&gt;
&lt;p&gt;Our first parsing method guides the parsing process: it peeks the current byte in the input to decide how to proceed.
In parser jargon, this is called a &lt;em&gt;predictive parser&lt;/em&gt;.
This is a simple and easy-to-understand strategy; it doesn&amp;rsquo;t always work (what if we can&amp;rsquo;t tell just from the next byte what to do?), but when it does we should use it.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;impl Parser {
    fn parse_value(&amp;amp;mut self) -&amp;gt; Result&amp;lt;BValue, Error&amp;gt; {
        match self.peek() {
            b&amp;#39;i&amp;#39; =&amp;gt; return self.parse_int(),
            b&amp;#39;l&amp;#39; =&amp;gt; return self.parse_list(),
            b&amp;#39;d&amp;#39; =&amp;gt; return self.parse_dict(),
            b&amp;#39;0&amp;#39;..=b&amp;#39;9&amp;#39; =&amp;gt; return self.parse_str(),
            c =&amp;gt; {
                return Err(format!(&amp;#34;parse value: invalid initial byte {:?}&amp;#34;, c as char));
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the parser is currently looking at the letter &lt;code&gt;&#39;i&#39;&lt;/code&gt;, we parse an integer and return its AST (or its error); if the parser is looking at a &lt;code&gt;&#39;l&#39;&lt;/code&gt; or &lt;code&gt;&#39;d&#39;&lt;/code&gt; we parse a list or a dictionary, respectively; if the next character is a digit, we parse a string; finally, if we see anything else, we report an error.&lt;/p&gt;
&lt;h3 id=&#34;integers&#34;&gt;Integers&lt;/h3&gt;
&lt;p&gt;Now that we have &lt;code&gt;parse_value&lt;/code&gt; to guide the parsing, we need to fill in the other parsing methods.
The first one we&amp;rsquo;ll tackle is &lt;code&gt;parse_int&lt;/code&gt;.
In Bencode, integers look like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# General form
i&amp;lt;digits&amp;gt;e

# Examples
i0e    (0)
i-3e   (-3)
i999e  (999)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our strategy for parsing will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read the leading &lt;code&gt;i&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Read an optional &lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Read the digits, accumulating them into a value&lt;/li&gt;
&lt;li&gt;Read the trailing &lt;code&gt;e&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Return the accumulated value&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;
&lt;b&gt;Exercise idea:&lt;/b&gt; modify `parse_int` to reject negative zero and numbers with leading zeros.
&lt;/aside&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;impl Parser {
    fn parse_int(&amp;amp;mut self) -&amp;gt; Result&amp;lt;BValue, Error&amp;gt; {
        self.expect(b&amp;#39;i&amp;#39;)?;

        let mult: i64 = if self.peek() == b&amp;#39;-&amp;#39; {
            self.advance();
            -1
        } else {
            1
        };

        let start_pos = self.pos;
        let mut value: i64 = 0;
        while !self.eof() &amp;amp;&amp;amp; self.peek().is_ascii_digit() {
            let b = self.advance();
            value = value * 10 + (b - b&amp;#39;0&amp;#39;) as i64;
        }

        if self.pos == start_pos {
            return Err(String::from(&amp;#34;invalid integers: no digits&amp;#34;));
        }

        self.expect(b&amp;#39;e&amp;#39;)?;
        return Ok(BValue::Int(mult * value));
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I think it&amp;rsquo;s pretty straight-forward; nothing that anyone would claim requires a CS degree or having read the Dragon Book.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We expect to see the byte &lt;code&gt;&#39;i&#39;&lt;/code&gt;; if we find anything else, we report an error;&lt;/li&gt;
&lt;li&gt;We peek for a minus sign; if it&amp;rsquo;s there, we advance &lt;code&gt;pos&lt;/code&gt; and set the multiplier to -1; otherwise we leave &lt;code&gt;pos&lt;/code&gt; where it is and set the multiplier to 1;&lt;/li&gt;
&lt;li&gt;We advance over the digits until we reach EOF or peek a byte that&amp;rsquo;s not an ascii digit; we accumulate the digits in a &lt;code&gt;i64&lt;/code&gt; value;&lt;/li&gt;
&lt;li&gt;After we exit the loop, we check that we actually read digits; if not, we report an error;&lt;/li&gt;
&lt;li&gt;We expect to see the byte &lt;code&gt;&#39;e&#39;&lt;/code&gt; ; if we find anything else, we report an error;&lt;/li&gt;
&lt;li&gt;We multiply the accumulated value with the multiplier to give it the right signedness and return a &lt;code&gt;BValue::Int&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not very hard and it will correctly parse Bencode integers, just like the nom version.&lt;/p&gt;
&lt;h3 id=&#34;strings&#34;&gt;Strings&lt;/h3&gt;
&lt;p&gt;Next up, string.
They have the following format:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# General form
&amp;lt;integer&amp;gt;:&amp;lt;bytes&amp;gt;

# Examples
0:        (&amp;#34;&amp;#34;)
3:foo     (&amp;#34;foo&amp;#34;)
3:foobar  (&amp;#34;foo&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As with integers, we&amp;rsquo;ll only need our small utility methods glued with some loops and if statements.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;impl Parser {
    fn parse_str(&amp;amp;mut self) -&amp;gt; Result&amp;lt;BValue, Error&amp;gt; {
        let mut len: usize = 0;
        while !self.eof() &amp;amp;&amp;amp; self.peek().is_ascii_digit() {
            let b = self.advance();
            len = len * 10 + (b - b&amp;#39;0&amp;#39;) as usize;
        }

        self.expect(b&amp;#39;:&amp;#39;)?;

        let mut buf = String::new();
        for _ in 0..len {
            let b = self.advance();
            if b == 0 {
                return Err(String::from(&amp;#34;invalid string: reached EOF&amp;#34;));
            }
            buf.push(b as char);
        }
        return Ok(BValue::Str(buf));
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;We start by reading the digits of the length of the string in exactly the same way that we did for integers. One difference though is that we don&amp;rsquo;t check to make sure that there actually were digits, because we know there is at least one: &lt;code&gt;parse_value&lt;/code&gt; called us because it had peeked a leading digit.&lt;/li&gt;
&lt;li&gt;We consume a colon or report an error.&lt;/li&gt;
&lt;li&gt;We consume &lt;code&gt;len&lt;/code&gt; bytes, pushing them into a String; if we encounter EOF before we&amp;rsquo;ve read all the characters, we report an error.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two parsing functions down, two more to go.&lt;/p&gt;
&lt;h3 id=&#34;lists-and-dictionaries&#34;&gt;Lists and dictionaries&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s tackle lists and dictionaries at the same time.
Their definitions will be recursive: they will read values by calling &lt;code&gt;parse_value&lt;/code&gt;.
Recursion can be scary sometimes, but as we&amp;rsquo;ll see, it makes the parsing methods very short.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;impl Parser {
    fn parse_list(&amp;amp;mut self) -&amp;gt; Result&amp;lt;BValue, Error&amp;gt; {
        self.expect(b&amp;#39;l&amp;#39;)?;
        let mut values: Vec&amp;lt;BValue&amp;gt; = Vec::new();
        while !self.eof() &amp;amp;&amp;amp; self.peek() != b&amp;#39;e&amp;#39; {
            values.push(self.parse_value()?);
        }
        self.expect(b&amp;#39;e&amp;#39;)?;
        return Ok(BValue::List(values));
    }

    fn parse_dict(&amp;amp;mut self) -&amp;gt; Result&amp;lt;BValue, Error&amp;gt; {
        self.expect(b&amp;#39;d&amp;#39;)?;
        let mut values: Vec&amp;lt;(String, BValue)&amp;gt; = Vec::new();
        while !self.eof() &amp;amp;&amp;amp; self.peek() != b&amp;#39;e&amp;#39; {
            let key = self.parse_str()?;
            let value = self.parse_value()?;
            if let BValue::Str(key) = key {
                values.push((key, value));
            } else {
                return Err(String::from(&amp;#34;invalid dict: keys must be strings&amp;#34;));
            }
        }
        self.expect(b&amp;#39;e&amp;#39;)?;
        return Ok(BValue::Dict(values));
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let&amp;rsquo;s focus on &lt;code&gt;parse_list&lt;/code&gt;, since it&amp;rsquo;s the simpler of the two.
We use &lt;code&gt;expect&lt;/code&gt; to consume the opening &lt;code&gt;&#39;l&#39;&lt;/code&gt;.
After we see the opening &lt;code&gt;&#39;l&#39;&lt;/code&gt; (technically, since &lt;code&gt;parse_value&lt;/code&gt; already saw the &lt;code&gt;&#39;l&#39;&lt;/code&gt;, it would be correct to use &lt;code&gt;advance()&lt;/code&gt;; I just like that the code for parsing a list shows the full structure of what a list looks like), we loop until EOF or until we peek an &lt;code&gt;&#39;e&#39;&lt;/code&gt;, and each time we call &lt;code&gt;parse_value()&lt;/code&gt; to get the next element from the list and store it in a vector.
This is the power of recursion: we could have lists within lists and this code would work correctly.
(We&amp;rsquo;d only get into trouble if the input had very deeply nested lists and blew the stack.)&lt;/p&gt;
&lt;p&gt;For dictionaries, it&amp;rsquo;s the same thing: we use &lt;code&gt;parse_str()&lt;/code&gt; to read the key and &lt;code&gt;parse_value&lt;/code&gt; to read the value.&lt;/p&gt;
&lt;h3 id=&#34;putting-a-bow-on-it&#34;&gt;Putting a bow on it&lt;/h3&gt;
&lt;p&gt;At this point, we got a fully functional parser.
We can now add one method to wrap it nicely.
The &lt;code&gt;parse()&lt;/code&gt; method will be our entry point; it will call &lt;code&gt;parse_value()&lt;/code&gt; to get a Bencode value and then ensure that there&amp;rsquo;s no extra garbage in the input.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;impl Parser {
    pub fn parse(&amp;amp;mut self) -&amp;gt; Result&amp;lt;BValue, Error&amp;gt; {
        let value = self.parse_value()?;
        if self.eof() {
            return Ok(value);
        } else {
            return Err(String::from(&amp;#34;garbage at the end of the input string&amp;#34;));
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And there we go, a complete parser in about 150 lines of simple, beginner-level code!
No need for an extra dependency, no need to learn yet another API, no need to remember the intricacies of closures in Rust.
Just plain old, boring code.&lt;/p&gt;
&lt;h2 id=&#34;pros-and-cons&#34;&gt;Pros and cons&lt;/h2&gt;
&lt;p&gt;Now, let&amp;rsquo;s talk about the pros and cons of writing your own parser by hand.
This is computer science after all, which means that there&amp;rsquo;s no &lt;em&gt;One Solution To Rule Them All&lt;/em&gt;, only trade-offs to be weighed.
Let&amp;rsquo;s start with the cons.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s easier to mess up. For example, we can make a mistake with &lt;code&gt;pos&lt;/code&gt; and be pointing not exactly where we should be. Without good test coverage, a bug could lurk in a seldom-taken path and only appear in production.&lt;/li&gt;
&lt;li&gt;No shared &amp;ldquo;parsing language&amp;rdquo; between projects. Everyone on the project needs to learn how &lt;em&gt;this&lt;/em&gt; particular parser works; they don&amp;rsquo;t benefit (as much) from past experience.&lt;/li&gt;
&lt;li&gt;It takes more code. If we want to whip out a small parser in a couple minutes, the hand-written approach will require more code, more typing, and will likely take more time than using a parsing library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the pros of the hand-written approach.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simpler code. As we saw, we only needed simple programming language features to build our Bencode parser. It&amp;rsquo;s not rare for parsing libraries to lean into more complex features, like closures, macros, traits, etc. This makes it easier for people to jump into the code (i.e., they don&amp;rsquo;t have to learn an external library) and it plays nicer with a debugger.&lt;/li&gt;
&lt;li&gt;Better error messages. One reason most production-level compilers have hand-written parsers is to give better error messages. When we can easily look at the state of the parser and have specific things for our language, it&amp;rsquo;s easier to give the user a clear message; in parsers generated by libraries, the error messages are often more generic and give less context.&lt;/li&gt;
&lt;li&gt;Performance. We didn&amp;rsquo;t spend one iota of energy in making our Bencode parser fast, but in my own tests, it runs about 3x faster than the nom-based parser.&lt;/li&gt;
&lt;li&gt;Fewer dependencies. Modern development relies very heavily on third-party libraries, with all the problems that can entail (e.g., left-pad). In Rust, extra dependencies can make the already-slow compile times even slower. Avoiding a third-party library avoids those extra liabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether a hand-written parser or a library is preferable will depend on the project, but also on what you value.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You can see the whole parser in &lt;a href=&#34;https://play.rust-lang.org/?version=stable&amp;amp;mode=debug&amp;amp;edition=2021&amp;amp;gist=97a6ee4c432abfe92f71b26346e8fd9f&#34;&gt;the Rust playground&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you started reading this post thinking that parsing was difficult and needed specialized tools, I hope that this wall of text (and code) has helped you see that it&amp;rsquo;s actually much simpler and easier than it might appear.
Of course, there are languages that are harder to parse than others and which will require more effort.
Bencode was relatively easy, but other languages might require more involved techniques, e.g., if we can&amp;rsquo;t predict the next parsing method to call from just looking at the current byte, we may need to use a backtracking algorithm, which is harder, but in general, you&amp;rsquo;ll probably find that predictive, recursive-descent parser are more often applicable than they are insufficient.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Just: the most reductive word in software development</title>
      <link>https://vfoley.xyz/just/</link>
      <pubDate>Sun, 01 May 2022 22:14:06 -0500</pubDate>
      
      <guid>https://vfoley.xyz/just/</guid>
      <description>&lt;p&gt;&lt;i&gt;(Intentionally provocative title.)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Do you use the word “just”? Have you ever said something like “oh, we &lt;em&gt;just&lt;/em&gt; need to implement that interface for this new type” or “it’s &lt;em&gt;just&lt;/em&gt; a small bash script” or something to that effect? I have, many times, and still catch myself saying “just” even though I’m trying to exorcise that word out of my vocabulary.&lt;/p&gt;
&lt;p&gt;I don’t like the word “just”. “Just” is extremely reductive. “Just” diminishes the complexity of the problems we work on and it diminishes the effort that people put into making solutions.&lt;/p&gt;
&lt;p&gt;Here’s an example scenario. Suppose we have two services, Alpha, which writes data in S3, and Beta which reads data from disk. Alice has been tasked with making Beta process the data generated by Alpha. Since the output format of Alpha isn’t the input format of Beta, Alice will have to do something to make them work together. Bob, always helpful (/s), says to “just write a bash script to download the files to Beta’s server.” Right Bob, &lt;em&gt;just&lt;/em&gt; a bash script, how hard can that be?&lt;/p&gt;
&lt;p&gt;Actually, there can be a lot of difficulties that lay ahead for Alice. Here are some from the top of my head:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bash is notoriously hard to get right: spaces can change the meaning of statements, incorrect quoting can cause bugs, etc.&lt;/li&gt;
&lt;li&gt;How will credentials to the S3 bucket(s) be made available to the bash script?&lt;/li&gt;
&lt;li&gt;How will the bash script be invoked?&lt;/li&gt;
&lt;li&gt;Is it sufficient to download the data or must extra transformations be performed?&lt;/li&gt;
&lt;li&gt;Are there race conditions between the download and Beta’s processing that need to be considered?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Though the script’s job is conceptually simple—bring data from S3 to disk—Alice actually has quite a bit of work on her plate. It’s not just a bash script, Bob, it’s a whole project! Would &lt;em&gt;you&lt;/em&gt; like it if someone made an off-hand comment about the project that you work on as &lt;em&gt;just&lt;/em&gt; fill in the blank?&lt;/p&gt;
&lt;p&gt;Another problem with Bob saying to &lt;em&gt;just&lt;/em&gt; write a bash script is that PMs might take his word that it’s just a bash script and under-estimate the time and effort required for the feature, possibly derailing the schedule of other teams.&lt;/p&gt;
&lt;p&gt;Let’s be careful about using the word “just”: computer science and programming are interesting and complex endeavours, what we may think is just may actually have a lot more nuance and complexity than we imagine at first.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Thank you to Mathieu Lapointe for reviewing a draft of this article and suggesting improvements.&lt;/i&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>On &#39;Clean Code&#39;</title>
      <link>https://vfoley.xyz/clean-code/</link>
      <pubDate>Fri, 12 Nov 2021 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/clean-code/</guid>
      <description>&lt;p&gt;Many programming books give advice on how we can make our code clean. It seems to be quite a lucrative industry, because these keeping coming out year after year and programmers keep buying them.&lt;/p&gt;
&lt;p&gt;Unfortunately, these books mostly concern themselves with what the &lt;em&gt;text&lt;/em&gt; of the code ought to look like, and not with what the &lt;em&gt;code itself&lt;/em&gt; ought to be.
They give advice such as &amp;ldquo;use meaningful names&amp;rdquo;, &amp;ldquo;keep methods short&amp;rdquo;, &amp;ldquo;prefer dynamic dispatch to &lt;code&gt;switch&lt;/code&gt;&amp;rdquo;, &amp;ldquo;depend upon abstractions, not concretions&amp;rdquo;, etc., but programs that abide by that advice are not magically readable or clean.
(In fact, it seems that the more of this advice that we apply to a program, the more we create a &amp;ldquo;clean mess&amp;rdquo;.)
But if we got the core of the program wrong&amp;mdash;solving the wrong problem, using the wrong tool, having piles of unnecessary abstractions&amp;mdash;no amount of advice about using private fields instead of public ones is going to meaningfully improve our program.&lt;/p&gt;
&lt;p&gt;These books should be understood as our industry&amp;rsquo;s &lt;em&gt;Strunk and White&lt;/em&gt; or &lt;em&gt;The Chicago Manual of Style&lt;/em&gt;: the advice they give on what &lt;em&gt;text&lt;/em&gt; ought to look like can be useful, but if an article is uninteresting, readers won&amp;rsquo;t care our about our usage of oxford commas.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s make sure when we review our peers&amp;rsquo; code that we don&amp;rsquo;t miss the forest for the trees and give them endless suggestions about how they could make their code &amp;ldquo;cleaner&amp;rdquo; by changing superficial details and instead focus on whether their general approach to the problem is sound or whether new requirements justify a different overall architecture.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rust 2022</title>
      <link>https://vfoley.xyz/rust-2022/</link>
      <pubDate>Wed, 20 Oct 2021 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/rust-2022/</guid>
      <description>&lt;p&gt;In the last few years, at the end of the year, the Rust Development Team asks people to write blog entries about their wishes for the next year.
The new year is still a bit off and no call for such posts has yet been made in 2021, but there are a few things that I have in mind and that I want to write about right now.
So without further ados, here is my wish list for Rust in 2022&lt;/p&gt;
&lt;h2 id=&#34;compile-times&#34;&gt;Compile times&lt;/h2&gt;
&lt;p&gt;I wrote about compile times at the end of &lt;a href=&#34;https://vfoley.xyz/rust-2019/&#34;&gt;2018&lt;/a&gt; and in 2021 I want to point at that blog post and say: &amp;ldquo;that&amp;rdquo;.
It&amp;rsquo;s depressing how little things have improved &amp;mdash; from the perspective of a user &amp;mdash; when it comes to compile times.
I work with a wonderful team on a product in Rust, but though our repository is not even 40,000 lines of code, it takes &lt;strong&gt;such&lt;/strong&gt; a long time to build.
It&amp;rsquo;s roughly 4 minutes for a debug build from scratch and 10 minutes for a release build from scratch; incremental builds in debug take about 90 seconds and it&amp;rsquo;s about 3 and a half minutes in release mode.
This is an absolute killer of productivity.
Every time that I make a small change &amp;mdash; even just adding a &lt;code&gt;dbg!()&lt;/code&gt; statement in a function &amp;mdash; I have to sit and wait for Rust to finish re-building and re-linking the project.&lt;/p&gt;
&lt;p&gt;Some may argue that a lot of progress has been made since 2018 and will point to charts that show the compile times of various Rust projects going down month after month, year after year.
And although they are technically right, it doesn&amp;rsquo;t matter.
I&amp;rsquo;m still sitting in front of my computer, waiting minutes for a build, getting bored, going on lobste.rs, and losing my flow and concentration.
The compile times of Rust are improving, but they&amp;rsquo;re not even within the ballpark of being acceptable.&lt;/p&gt;
&lt;p&gt;Another thing that some people say is to control dependencies.
I agree whole-heartedly with this point: bringing in large dependencies in order to use only a tiny fraction of their functionality is not usually a good trade.
(I recently stopped using a library to do ISO-8859-1 to UTF-8 conversion when I discovered that it took only two lines of code to do it by hand. Five dependencies gone, just like that!)
Unfortunately, some of the most common and useful crates in the Rust ecosystem are big and slow to build.
For instance, we use tokio, serde, and hyper in some of our projects; they add &lt;em&gt;minutes&lt;/em&gt; to the build times, but what&amp;rsquo;s the alternative?
We have our own expertise and async runtimes and web servers are not it.&lt;/p&gt;
&lt;p&gt;I hope that Rust build times improve in 2022. We need them to improve drastically. Not a by a few percent, but by an order of magnitude.&lt;/p&gt;
&lt;h2 id=&#34;debugging&#34;&gt;Debugging&lt;/h2&gt;
&lt;p&gt;Since compiling takes so long, doing exploration of a code base by sprinkling in &lt;code&gt;dbg!()&lt;/code&gt; statements is not a great experience.
I tried using &lt;code&gt;rust-gdb&lt;/code&gt; to follow code paths and inspect data, and although it works well enough for simple programs, it&amp;rsquo;s not without its issues.&lt;/p&gt;
&lt;p&gt;The first problem is probably not super complex to tackle (famous last words): Strings within structs are not pretty-printed.
Compare below the output of printing a variable of type &lt;code&gt;String&lt;/code&gt; and a variable which is a struct containing a &lt;code&gt;String&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) p a
$1 = &amp;#34;Hello, world!&amp;#34;

(gdb) p b
$2 = dbg_demo::MyStruct {inner_string: alloc::string::String {vec: alloc::vec::Vec&amp;lt;u8, alloc::alloc::Global&amp;gt; {buf: alloc::raw_vec::RawVec&amp;lt;u8, alloc::alloc::Global&amp;gt; {ptr: core::ptr::unique::Unique&amp;lt;u8&amp;gt; {pointer: 0x55555559baa0, _marker: core::marker::PhantomData&amp;lt;u8&amp;gt;}, cap: 13, alloc: alloc::alloc::Global}, len: 13}}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The same happens with other common types: vectors, sets, maps, etc. It would be very nice if printing and navigating a struct in the debugger did not expose the internals of those objects (unless explicitly required I suppose).&lt;/p&gt;
&lt;p&gt;The other thing that should be worked on is async support.
With rust-gdb, if you set a breakpoint on an async function, it&amp;rsquo;ll immediately return.
In a sense, it&amp;rsquo;s understandable: the function doesn&amp;rsquo;t do any work per se; it creates and returns a &lt;code&gt;Future&lt;/code&gt; that will do the work, but from a user-experience perspective, not being able to debug async functions the same way we debug regular functions is very problematic.&lt;/p&gt;
&lt;p&gt;Normally, I wouldn&amp;rsquo;t care too much about the state of debug support (I&amp;rsquo;ve never been quite good at using debuggers), but given that compile times are such as they are, we should be able to extract as much value from one compile as possible.
Improved debug support would go a long way toward that.&lt;/p&gt;
&lt;h2 id=&#34;more-restraint-in-the-implementation-of-features&#34;&gt;More restraint in the implementation of features&lt;/h2&gt;
&lt;p&gt;This one is more of a &amp;ldquo;get off my lawn you darn kids&amp;rdquo; rant from a programmer who&amp;rsquo;s gaining more grey hair each month, so take with a grain of salt.
Programming languages cannot be everything for everyone and the job of language designers is to be judicious in the choice of features they include and even more judicious in the choice of features they omit.
This could be a reddit-tinted view of the situation, but it appears to me that a number of features are coming down the pipe that will make the language more complex, harder to learn, harder to master (and worst of all, harder to convince other people &lt;strong&gt;not&lt;/strong&gt; to use those features) that address very niche cases.&lt;/p&gt;
&lt;p&gt;If I were 5&amp;ndash;10 years younger, I&amp;rsquo;d probably be very excited at those new advanced language features; as an increasingly grumpy and crusty coder, those new features scare me, because I&amp;rsquo;m afraid (1) that I won&amp;rsquo;t be able to properly learn them (I still haven&amp;rsquo;t fully grokked Pin, GATs are probably going to be something I want to avoid, and I&amp;rsquo;m really hoping the push to make Rust Haskell with type families and GADTs will not come to be); (2) that other programmers will start using those features just because they can and not because they are necessary to the solution to the problems they are solving.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Making Reasonable Use of Computer Resources: Part 2</title>
      <link>https://vfoley.xyz/reasonable-use-2/</link>
      <pubDate>Sat, 28 Aug 2021 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/reasonable-use-2/</guid>
      <description>&lt;p&gt;In my &lt;a href=&#34;https://vfoley.xyz/reasonable-use&#34;&gt;last post&lt;/a&gt; I made the case that programmers should try and write their software in a way that makes &lt;em&gt;reasonable&lt;/em&gt; use of the resources of the computer. By reasonable use, I didn&amp;rsquo;t mean to try and perform every crazy micro-optimization possible to extract every last speck of performance from the machine: instead, I meant to have &lt;a href=&#34;https://www.youtube.com/watch?v=MC1EKLQ2Wmg&#34;&gt;mechanical sympathy&lt;/a&gt;, to write software in a way that works with the hardware rather than against it, and to take the specific problem into consideration when creating a solution.&lt;/p&gt;
&lt;p&gt;That article had an example of how being mindful of the CPU cache can make one algorithm nearly 16 times faster than another, even though they have the same algorithmic complexity. I&amp;rsquo;ve been wanting to find a more real-world example, and this week, one feel in my lap.&lt;/p&gt;
&lt;p&gt;A year ago, Mark Litwintschik wrote &lt;a href=&#34;https://tech.marksblogg.com/fast-ip-to-hostname-clickhouse-postgresql.html&#34;&gt;an article&lt;/a&gt; where he extracted the domain names from a 12 GiB gzip file containing 1.27 billion lines of JSON and created an &lt;code&gt;ip,domain&lt;/code&gt; CSV file. That program was written in Python and took more than a day to run!&lt;/p&gt;
&lt;p&gt;Last week, Mark wrote &lt;a href=&#34;https://tech.marksblogg.com/rdns-domain-name-tld-extract-rust.html&#34;&gt;a follow-up article&lt;/a&gt; detailing a new program to do the same job, one written in Rust. Rust is a statically-typed language, it&amp;rsquo;s compiled to native code, and the compiler uses LLVM to apply many optimizations, so we&amp;rsquo;d expect this version to be faster. And it is: the Rust version processed the data in 48 minutes. After he shared his article on &lt;a href=&#34;https://lobste.rs/s/a1jbrq/faster_top_level_domain_name_extraction&#34;&gt;lobste.rs&lt;/a&gt;, Mark received suggestions to make the program faster and has since brought the processing down to 30 minutes. His new program is 50 times faster than his original &amp;mdash; a much better use of the machine&amp;rsquo;s resources! And yet, when I initially read the article, I thought that 48 minutes sounded slow.&lt;/p&gt;
&lt;aside&gt;
I started working on this before Mark updated his post with the 30 minutes program. But even if I had read the article after he updated it, I would have still thought that 30 minutes sounded kind of slow.
&lt;/aside&gt;
&lt;p&gt;Thankfully, Mark&amp;rsquo;s article gave links to the dataset and to the third-party library he was using, and he shared his Rust code and the bash commands he used to execute his program. It made it very easy to replicate his experiment.&lt;/p&gt;
&lt;p&gt;Mark&amp;rsquo;s program works in four phases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read and decompress&lt;/li&gt;
&lt;li&gt;Parse JSON&lt;/li&gt;
&lt;li&gt;Call out to &lt;a href=&#34;https://github.com/dovahcrow/tldextract-rs/&#34;&gt;tldextract-rs&lt;/a&gt; to extract the domain name&lt;/li&gt;
&lt;li&gt;Write a line of output&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first thing I did was very simple: I timed how long it took to &lt;code&gt;zcat&lt;/code&gt; the input. This would help me gauge how long steps 1 and 4 took together. I wanted to know if I was right to think that 48 minutes was slow or if my expectations were wrong.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ time zcat rdns_xaa.json.gz &amp;gt;/dev/null

real    1m34.420s
user    1m34.047s
sys     0m0.364s
&lt;/code&gt;&lt;/pre&gt;&lt;aside&gt;
Mark&#39;s article splits the original 12 GiB file in 4 parts and runs 4 parallel instances of his program on the shards. That&#39;s why I use shards to do my timings.
&lt;/aside&gt;
&lt;p&gt;So roughly a minute and a half to decompress, read, and write. I didn&amp;rsquo;t think that parsing JSON would be much slower than decompressing a gzip file, so most of the time has to be spent in phase 3, extracting the domain name. Since the operation sounds quite simple and straight-forward (find the longest top-level domain suffix, take the substring to the left until a period or the beginning of the string is encountered), I suspected that something was probably being wasteful there.&lt;/p&gt;
&lt;p&gt;Next, I ran Mark&amp;rsquo;s original program to know how long it took to run on my machine.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ perf stat -dd ./target/release/tldextract rdns_xaa.json.gz &amp;gt;/dev/null

 Performance counter stats for &amp;#39;./target/release/tldextract rdns_xaa.json.gz&amp;#39;:

      1,644,491.19 msec task-clock                #    1.000 CPUs utilized
             8,526      context-switches          #    0.005 K/sec
                72      cpu-migrations            #    0.000 K/sec
             1,103      page-faults               #    0.001 K/sec
 6,678,553,292,544      cycles                    #    4.061 GHz                      (38.46%)
18,119,341,562,549      instructions              #    2.71  insn per cycle           (46.15%)
 3,952,769,540,665      branches                  # 2403.643 M/sec                    (46.15%)
     9,984,392,711      branch-misses             #    0.25% of all branches          (46.15%)
 3,738,006,667,501      L1-dcache-loads           # 2273.048 M/sec                    (46.15%)
    39,713,107,241      L1-dcache-load-misses     #    1.06% of all L1-dcache accesses  (46.15%)
     1,216,763,228      LLC-loads                 #    0.740 M/sec                    (30.77%)
        26,340,299      LLC-load-misses           #    2.16% of all LL-cache accesses  (30.77%)
   &amp;lt;not supported&amp;gt;      L1-icache-loads
   211,529,207,164      L1-icache-load-misses                                         (30.77%)
 3,738,968,599,010      dTLB-loads                # 2273.632 M/sec                    (30.77%)
        18,483,670      dTLB-load-misses          #    0.00% of all dTLB cache accesses  (30.77%)
        38,106,464      iTLB-loads                #    0.023 M/sec                    (30.77%)
       382,508,684      iTLB-load-misses          # 1003.79% of all iTLB cache accesses  (30.77%)

    1644.802173800 seconds time elapsed

    1618.366720000 seconds user
      26.137782000 seconds sys
&lt;/code&gt;&lt;/pre&gt;&lt;center&gt;
&lt;small&gt;&lt;i&gt;I like to use `perf stat -dd` instead of `time`; it gives a more complete picture&lt;/i&gt;&lt;/small&gt;
&lt;/center&gt;
&lt;p&gt;The program finished in 27 minutes on my machine. While the program was running, I also ran &lt;code&gt;perf top&lt;/code&gt; to look at which functions were taking the most time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://vfoley.xyz/images/tld-perf-top.png&#34; alt=&#34;perf top&#34;&gt;&lt;/p&gt;
&lt;p&gt;When I skimmed the original program and the third-party library, I thought that they allocated a lot. For example, the &lt;code&gt;std::io::Lines&lt;/code&gt; iterator allocates a new string for every line of input and when the line goes out of scope, it&amp;rsquo;s freed. Given the size of the input, that&amp;rsquo;s 1.27 billion allocations and deallocations. &lt;code&gt;perf top&lt;/code&gt; shows malloc/realloc/free taking nearly 10% of the total execution time, so they&amp;rsquo;re a problem.&lt;/p&gt;
&lt;p&gt;But the real big issue is in the third-party library to manipulate domains. Since domains are allowed to have Unicode in them, a lot of time is spent in IDNA code. But is that really necessary? Does the data that we manipulate require that we impose the extra cost of Unicode domain names upon us?&lt;/p&gt;
&lt;p&gt;What I found by inspecting the data is that all the JSON objects contain only ASCII characters and only 20 objects out of 1.27 billion contain the substrings &lt;code&gt;\u&lt;/code&gt; or &lt;code&gt;\U&lt;/code&gt; (JSON unicode escape sequences). That means that the original program is using a library that makes processing every line slower for the benefit of only 0.00000157% of the lines. Instead of solving the generic case, &lt;a href=&#34;https://youtu.be/rX0ItVEVjHc?t=1697&#34;&gt;let&amp;rsquo;s solve the common case&lt;/a&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ parallel &amp;#34;zcat {} | grep -P &amp;#39;[^\000-\177]&amp;#39; | wc -l&amp;#34; ::: rdns_xa*.gz
0
0
0
0

$ parallel &amp;#34;zcat {} | grep -iF &amp;#39;\u&amp;#39; | wc -l&amp;#34; ::: rdns_xa*.gz
14
1
5
0
&lt;/code&gt;&lt;/pre&gt;&lt;center&gt;
&lt;small&gt;&lt;i&gt;Bash commands to search for Unicode in the data&lt;/i&gt;&lt;/small&gt;
&lt;/center&gt;
&lt;p&gt;So given what we know, here&amp;rsquo;s the plan for a (hopefully) faster program. Like the original program we&amp;rsquo;ll use flate2&amp;rsquo;s GzDecoder to decompress the data. We are not going to use the lines iterator, instead we&amp;rsquo;re going to use the method &lt;code&gt;BufReader::read_line&lt;/code&gt; which allows us to re-use the same buffer, so we only need to allocate once for all the lines. When we have a line, we&amp;rsquo;re going to do a quick linear search for the substring &lt;code&gt;\u&lt;/code&gt;; if it&amp;rsquo;s found, we write that line to a file called &lt;code&gt;rejected.json&lt;/code&gt; that we can process separately and move on to the next line. We&amp;rsquo;re going to use serde_json instead of json, because &lt;a href=&#34;https://github.com/serde-rs/json-benchmark&#34;&gt;it&amp;rsquo;s a bit faster&lt;/a&gt;. To find the top-level domain, we&amp;rsquo;ll create a HashSet of all the domain suffixes (obtained from &lt;a href=&#34;http://publicsuffix.org/list/public_suffix_list.dat&#34;&gt;here&lt;/a&gt;) and we&amp;rsquo;ll find the longest suffix we can; once we have that suffix, we can extract the string to its left until we find a period or the beginning of the string. Finally, we write out to stdout, but not with &lt;code&gt;println!&lt;/code&gt;, but with a pre-locked Stdout object.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ perf stat -dd ./target/release/vfb-tldextract public_suffix_list.dat rdns_xaa.json.gz rejected_xaa.json &amp;gt;/dev/null
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627471863\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.39\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627447667\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.40\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627444989\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.43\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627486727\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.45\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: processed 310673926 lines (14 rejected) in 155.272128427s

 Performance counter stats for &amp;#39;./target/release/vfb-tldextract ../tldextract/public_suffix_list.dat ../tldextract/rdns_xaa.json.gz rejected_xaa.json&amp;#39;:

        155,270.78 msec task-clock                #    1.000 CPUs utilized
               451      context-switches          #    0.003 K/sec
                 1      cpu-migrations            #    0.000 K/sec
               345      page-faults               #    0.002 K/sec
   631,384,933,925      cycles                    #    4.066 GHz                      (38.46%)
 1,803,019,603,887      instructions              #    2.86  insn per cycle           (46.15%)
   365,196,577,639      branches                  # 2351.998 M/sec                    (46.15%)
     2,314,559,123      branch-misses             #    0.63% of all branches          (46.15%)
   379,148,826,483      L1-dcache-loads           # 2441.856 M/sec                    (46.15%)
     2,166,436,251      L1-dcache-load-misses     #    0.57% of all L1-dcache accesses  (46.15%)
        75,583,470      LLC-loads                 #    0.487 M/sec                    (30.77%)
        25,064,718      LLC-load-misses           #   33.16% of all LL-cache accesses  (30.77%)
   &amp;lt;not supported&amp;gt;      L1-icache-loads
       300,858,674      L1-icache-load-misses                                         (30.77%)
   379,351,678,372      dTLB-loads                # 2443.162 M/sec                    (30.77%)
           105,344      dTLB-load-misses          #    0.00% of all dTLB cache accesses  (30.77%)
           506,821      iTLB-loads                #    0.003 M/sec                    (30.77%)
         2,868,354      iTLB-load-misses          #  565.95% of all iTLB cache accesses  (30.77%)

     155.275422832 seconds time elapsed

     154.847572000 seconds user
       0.423987000 seconds sys
&lt;/code&gt;&lt;/pre&gt;&lt;center&gt;
&lt;small&gt;&lt;i&gt;
2 minutes and 35 seconds; 10 times faster than the original program and less that twice the time to just `zcat`.
&lt;/small&gt;&lt;/i&gt;
&lt;/center&gt;
&lt;p&gt;Now the final test, how long does it take to transform the four shards in parallel?&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ time /usr/bin/ls rdns*.json.gz | xargs -P4 -n1 -I{} sh -c &amp;#39;./vfb-tldextract public_suffix_list.dat {} {}.rejected.json &amp;gt;{}.csv&amp;#39;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627442231\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;41.185.37.10\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627473254\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;41.185.37.11\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627458666\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;41.185.37.12\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627479199\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;41.185.37.13\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627439294\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;41.185.37.14\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627471863\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.39\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627447667\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.40\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627444989\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.43\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627486727\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;152.149.215.45\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: cannot deserialize this line: &amp;#34;{\&amp;#34;timestamp\&amp;#34;:\&amp;#34;1627490888\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;210.35.32.3\&amp;#34;,\&amp;#34;type\&amp;#34;:\&amp;#34;ptr\&amp;#34;}\n&amp;#34;
vfb-tldextract: processed 310673940 lines (0 rejected) in 184.360843703s
vfb-tldextract: processed 310673926 lines (14 rejected) in 184.376276827s
vfb-tldextract: processed 310673939 lines (1 rejected) in 184.705608281s
vfb-tldextract: processed 310673935 lines (5 rejected) in 188.207680141s

real    3m8.222s
user    11m53.263s
sys     0m16.673s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;rsquo;s slower than just one shard at a time (I haven&amp;rsquo;t yet investigated why that is; my guess is that we&amp;rsquo;re maxing out the write speed of the disk) but still nearly 10x faster than the original program. And I think we did things that most programmers would be able to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get a base line for how fast we can &lt;code&gt;zcat&lt;/code&gt; a file&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;perf top&lt;/code&gt; to find some bottlenecks that can be addressed&lt;/li&gt;
&lt;li&gt;Look at the data to understand what the common case is&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And I think that the final program is something that most people reading this would probably have been able to do themselves.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to look at my code, it&amp;rsquo;s available on &lt;a href=&#34;https://github.com/gnuvince/vfb-tldextract&#34;&gt;Github&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Making Reasonable Use of Computer Resources</title>
      <link>https://vfoley.xyz/reasonable-use/</link>
      <pubDate>Sat, 31 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/reasonable-use/</guid>
      <description>&lt;p&gt;The computers sitting on our desks are incomprehensibly fast. They can perform more operations in one second than a human could in one hundred years. We live in an era of CPUs that can perform billions of instructions per second, tens of billions if we take multi-cores into account, of memory that can transfer data to the CPU at hundreds of gigabytes per second, of disks that support streaming reads of gigabytes per second. This era of incredibly fast hardware is also the era of programs that take tens of seconds to start from an SSD or NVMe disk; of bloated web applications that take many seconds to show a simple list, even on a broadband connection; of programs that process data at a thousandth of the speed we should expect. Software is laggy and sluggish &amp;mdash; and the situation shows little signs of improvement. Why is that?&lt;/p&gt;
&lt;p&gt;I believe that the main reason is that most of us who started programming after, say the year 2000, have never learned how to make &lt;strong&gt;reasonable use&lt;/strong&gt; of the computational resources at our disposal. In fact, most of our training has taught us to ignore the computer!&lt;/p&gt;
&lt;p&gt;Although our job is ostensibly to create programs that let users &lt;strong&gt;do stuff with their computers&lt;/strong&gt;, we place a greater emphasis on the development process and dev-oriented concerns than on the final user product. SICP contains a quote that I find to be a good summarization of the problem: &amp;ldquo;programs must be written for people to read, and only incidentally for machines to execute.&amp;rdquo; Many programmers find that quote wise and inspiring, but users are not interested in reading programs, they&amp;rsquo;re interested in executing them, fast. We can&amp;rsquo;t make programs that run fast if we write them in a way that is only &amp;ldquo;incidentally&amp;rdquo; executable. The computer is not an implementation detail that can be abstracted away and ignored &amp;mdash; it&amp;rsquo;s an integral part of the solution. A program that makes no room for the target machine in its design will inevitably run slower than one that does.&lt;/p&gt;
&lt;aside&gt;
People migrate to faster programs because faster programs allow users to do more. Look at examples from the past: the original Python-based bittorrent client was quickly overtaken by the much faster uTorrent; Subversion lost its status as the premier VCS to Git in large part because every operation was so much faster in Git; the improved grep utility, ack, is written in Perl and waning in popularity to the faster silversurfer and ripgrep; the Electron-based editor Atom has been all but replaced by VSCode, also Electron-based, but which is faster; Chrome became the king of browsers largely because it was much faster than Firefox and Internet Explorer. The fastest option eventually wins. Would your project survive if a competitor came along and was ten times faster?
&lt;/aside&gt;
&lt;p&gt;A common argument against taking the computer into account during the design phase of a program is &amp;ldquo;premature optimzation is the root of all evil.&amp;rdquo; Topics such as cache-friendliness, branch prediction, and parallelism are labeled as &amp;ldquo;optimization&amp;rdquo;, but really they should be labeled as &amp;ldquo;reasonable use&amp;rdquo;. Our users&amp;rsquo; computers have resources and we should design our programs in a way that they use those resources.&lt;/p&gt;
&lt;p&gt;Take the CPU cache for example. A simple program that shows what a massive impact good cache usage can have on performance is to sum the elements of a matrix row-by-row vs. column-by-column (here&amp;rsquo;s a &lt;a href=&#34;https://play.rust-lang.org/?version=stable&amp;amp;mode=release&amp;amp;edition=2018&amp;amp;gist=58f145598f757ec83498f92960336f70&#34;&gt;Rust Playground link&lt;/a&gt; that demonstrates this). In this example, the row-by-row is about 12&amp;ndash;16 times faster than the column-by-column, even though they have same Big-O complexity. The difference in performance is not due to an abstract, computer science factor, but due to a very concrete one: better use of the CPU cache. The row-by-row approach brings 16 floats in cache and uses them all before going back to memory; by contrast the column-by-column approach also brings 16 floats, but only uses one of them before going back to RAM, leaving 15 values unused &amp;mdash; that&amp;rsquo;s 94% waste.&lt;/p&gt;
&lt;a href=&#34;https://twitter.com/bmcnett/status/1043332565308923904&#34;&gt;
&lt;img alt=&#34;Going to the store for one slice of bread?&#34; src=&#34;https://vfoley.xyz/images/slice-bread.png&#34; /&gt;
&lt;/a&gt;
&lt;p&gt;There are a few things we should note about this example. First, the compiler did not optimize the code for us. We often hear that programmers can&amp;rsquo;t beat an optimizing compiler, but in this case we did.  We only needed to change the order of the loops, but the Rust compiler which uses the LLVM backend, did not do it. Maybe the famed sufficiently smart compiler would, but for the foreseeable future, arranging data in a way that it can be processed efficiently will not be the compiler&amp;rsquo;s job &amp;mdash; it&amp;rsquo;ll be ours. Second, we can&amp;rsquo;t get that speed-up without taking the actual hardware into account in our solution. We do not write code for abstract, idealized, or fictitious machines: we write code that runs on the CPUs of our users &amp;mdash; Intel, AMD, Apple, etc. These CPUs have caches and it&amp;rsquo;s perfectly reasonable to write code that works well with the hardware rather than against it. Third, a 16x speed-up may only be a constant factor in complexity theory, but to a user it can be the difference between a program being pleasant to use and being extremely frustrating. Or the difference between a small and large AWS bill. And finally, we should not consider this to be an optimization: we&amp;rsquo;re making use of a resource that&amp;rsquo;s there. The users paid the full price of their CPU, let&amp;rsquo;s try and give them their money&amp;rsquo;s worth.&lt;/p&gt;
&lt;aside&gt;
In my mind, an optimization would be trying to pack 17 floats in a cache line that can fit 16. Doing this at the beginning of the project would indeed be premature.
&lt;/aside&gt;
&lt;p&gt;I expect that many will think of the old aphorism &amp;ldquo;make it work, make it right, make it fast&amp;rdquo; and argue that taking the machine into account when first writing the program is focusing on &amp;ldquo;make it fast&amp;rdquo; before we even got to &amp;ldquo;make it work&amp;rdquo;. I get that, but if we do things in order and make our program work and then make it right, when it&amp;rsquo;s time to make it fast, we often realize that our design works against us and we have to undo/redo a lot of the work we did to make the program work and to make it right.&lt;/p&gt;
&lt;p&gt;For example, we may have arranged our data in a row-oriented fashion aka array of structs and we realize that in order to speed up our program we would need column-oriented storage, aka struct of arrays. Changing a program from one form to the other is a major re-architecture project, and one that may not be feasible if there&amp;rsquo;s a deadline approaching and that&amp;rsquo;s more slow software on the market and the aphorism becomes &amp;ldquo;make it work, make it right, dream of making it fast&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;So how do we write code that runs reasonably quickly on modern machines? We start by getting into the habit of not just thinking about the model of what we write, but also the mechanics: how many bytes are needed to represent a data structure? Are there many pointers that will cause cache misses? Is the data organized in a way that the branch prediction will be right often? Would it be easy to slice the work among multiple threads?&lt;/p&gt;
&lt;p&gt;Another way is to start thinking in terms of batches and systems. Suppose we are writing a tokenizer for a programming language; if we think about tokens as completely independent pieces of data, each one needs to carry the string associated with the token (e.g., &lt;code&gt;struct Token { tag: Tag, text: String, ... }&lt;/code&gt;). If instead we think of tokenization as a system and of tokens as dependents of this system, we can create a string pool in the tokenizer and tokens can have an index into the pool for their associated text. This saves memory by not having to duplicate strings and makes the tokens smaller, which means more can fit in one cache line.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dbartolini/data-oriented-design&#34;&gt;Data-oriented
design&lt;/a&gt; is an
approach to programming that concerns itself with such questions. At the moment, most data-oriented design practitioners work in the game industry, but the insights are valuable in every field. (For example, Andy Kelly spoke highly of data-oriented design in the &lt;a href=&#34;https://ziglang.org/download/0.8.0/release-notes.html#Reworked-Memory-Layout&#34;&gt;Zig 0.8.0 release notes&lt;/a&gt;.) If you&amp;rsquo;ve never been exposed to data-oriented design, it can be a bit of a shock &amp;mdash; a lot of the common &lt;em&gt;wisdom&lt;/em&gt; of programming (e.g., Uncle Bob&amp;rsquo;s SOLID principles) is eschewed and replaced with cold, hard engineering. It looks scary and different, but it&amp;rsquo;s what we need to do if we are to deliver software that is not orders of magnitude slower than it can be.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;My thanks to Mathieu Lapointe for reading early drafts of this article.&lt;/i&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Lesser Known Coding Fonts</title>
      <link>https://vfoley.xyz/lesser-known-coding-fonts/</link>
      <pubDate>Thu, 17 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/lesser-known-coding-fonts/</guid>
      <description>&lt;style&gt;
    table {
        font-family: monospace;
    }
    th {
        width: 170px;
        font-weight: normal;
    }
    th, td {
        border-left: 1px solid;
        border-right: 1px solid;
        border-top: 0px;
        border-bottom: 0px;
    }
    div.small {
        font-size: 10pt;
        color: #888;
    }
&lt;/style&gt;
&lt;!--
PLAN:
    1. I&#39;ve become more interested in fonts for programmers in past few months; looking at them all day, multiple purposes
    2. Great place to see fonts other programmers use: /r/unixporn
    3. My current impression: #1 is Hack, lots of system fonts, many open source fonts
    4. Here are 5 fonts that I see less often, but deserve attention

APL385:
    - Font for APL, lots of horizontal and vertical space, curviness and rounded terminators makes it look whimsical.
    - Easy to distinguish most characters, though the lack of slashed or dotted zero can cause confusion with the uppercase Oh.
    - At small sizes on Linux the font is jaggy

Go Mono:
    - Font from Go Project, only serif font in my list (little legs).
    - Easy to distinguish all characters, but the absence of a gap between underscores can be annoying for Python users.
    - Surprisingly readable at small sizes
    - There is a proportional version that is serviceable for code if that&#39;s your thing (it is Rob Pike&#39;s thing)

Sudo:
    - One programmer decided to draw his own coding font, been working on it since 2009
    - Easy to distinguish all characters
    - The digits are a bit shorter than uppercase letters
    - Some glyphs don&#39;t yet have their curves drawn and look pixelated (e.g., lowercase theta or superscript 3)
    - It has a Variable Open Font version, i.e., one font for regular, italics, bold, and bold italic.

Monoid:
    - Another coding font made by a programmer
    - Goal: extreme readability, even at very small sizes; it has a bitmap look (but isn&#39;t bitmapped)
    - Easy to distinguish all characters
    - Can be customized: before downloading you can change the shape of the characters `$01l`, the line spacing, and the tracking (horizontal spacing between characters)
    - Ligatures can be turned on or off
    - Companion Monoisome

Input Mono:
    - Only non-free font in the list
    - Free for private use, must purchase a license to use in a book or your website
    - Drawn by a professional font designer, David Jonathan Ross
    - Easy to distinguish all characters
    - Can be customized: before downloading you change the shape of the characters `0agil{*}`, the line spacing.
    - Available in three widths: regular, condensed, compressed
    - Powerline-ready out of the box
    - There&#39;s also a serif and a sans-serif proportional version
--&gt;
&lt;p&gt;In the past few months, I&amp;rsquo;ve become interested&amp;mdash;fascinated even&amp;mdash;by programming fonts.
As programmers we look at text all day: code, logs, command outputs, monitoring tools, etc.
If we&amp;rsquo;re going to be looking at text all day, we might as well make it easy and pleasant for our eyes to read that text.&lt;/p&gt;
&lt;p&gt;One great place to see the fonts used by other people is at &lt;a href=&#34;https://www.reddit.com/r/unixporn/&#34;&gt;/r/unixporn&lt;/a&gt;.
I have not conducted a thorough survey, but from my observations it seems that, currently, the most popular font for the ricers of /r/unixporn is &lt;a href=&#34;https://sourcefoundry.org/hack/&#34;&gt;Hack&lt;/a&gt;.
As we might expect, many use the built-in system fonts: DejaVu Sans Mono and Ubuntu Mono for Linux; Monaco, Menlo, and SF Mono on macOS.
High-quality open source fonts are also very well represented: Fira Code, Inconsolata, Iosevka, Noto, Roboto Mono, and Source Code Pro.&lt;/p&gt;
&lt;p&gt;In this post, I want to show five fonts that I don&amp;rsquo;t see as often on /r/unixporn, but which I believe deserve to be better known.
(Edit: ironically enough, this post cannot be posted on /r/unixporn, because they don&amp;rsquo;t accept content that isn&amp;rsquo;t screenshots, photos, or videos.)&lt;/p&gt;
&lt;h2 id=&#34;apl385-unicode&#34;&gt;APL385 Unicode&lt;/h2&gt;
&lt;p&gt;The first font I want to suggest is APL385 Unicode.
APL is a programming language where operations are denoted with operators.
In order to make APL code more readable, APL385 has generous spacing between lines and between characters.
The terminators (the end of strokes) are rounded which gives the font a fun, whimsical look.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://vfoley.xyz/font-screenshots/apl385.png&#34;&gt;&lt;img src=&#34;https://vfoley.xyz/font-screenshots/apl385.png&#34; alt=&#34;APL385 Unicode&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;div class=&#34;small&#34;&gt;(Click on the image to zoom)&lt;/div&gt;&lt;/center&gt;
&lt;p&gt;As a programming font, the majority of characters are easy to distinguish, however the lack of slashed or dotted zero can cause confusion with the uppercase Oh.
APL385 does not support Powerline glyphs, and there isn&amp;rsquo;t a patched version like there exists for other fonts.&lt;/p&gt;
&lt;p&gt;One thing to note, at least on Linux: at smaller font sizes, the hinting is very bad and the font looks very jaggy.
Not recommended if you like very small font sizes.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
    &lt;th&gt;Homepage&lt;/th&gt;
    &lt;td&gt;&lt;a href=&#34;http://apl385.com/fonts/&#34;&gt;http://apl385.com/fonts/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;License&lt;/th&gt;
    &lt;td&gt;Public domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Glyph count&lt;/th&gt;
    &lt;td&gt;769&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Weights&lt;/th&gt;
    &lt;td&gt;Regular&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Italics?&lt;/th&gt;
    &lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Ligatures?&lt;/th&gt;
    &lt;td&gt;No&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Customizable?&lt;/th&gt;
    &lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&#34;go-mono&#34;&gt;Go Mono&lt;/h2&gt;
&lt;p&gt;Go Mono is one of the typeface in the Go type family.
These fonts were created by the professional firm Bigelow &amp;amp; Holmes, and released under the BSD license.
Go Mono is the only serif font in this list.
(Serifs are the little “legs” at the end of some strokes.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://vfoley.xyz/font-screenshots/go-mono.png&#34;&gt;&lt;img src=&#34;https://vfoley.xyz/font-screenshots/go-mono.png&#34; alt=&#34;Go Mono&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;div class=&#34;small&#34;&gt;(Click on the image to zoom)&lt;/div&gt;&lt;/center&gt;
&lt;p&gt;Like most programming fonts, all the characters are easy to distinguish, though I will point out the lack of spacing between consecutive underscores; this can be annoying to people who code in languages like Python where the double-underscore is used quite often.
Go Mono is easy to read at very small sizes: even with my aging eyes, it&amp;rsquo;s not difficult for me to make out words at 8 points (although I recommend using a larger font size!)
Like the majority of coding fonts, Go Mono comes in two weights, regular and bold, and it has an italic version.&lt;/p&gt;
&lt;p&gt;As the name suggests, Go Mono is monospaced; the proportional typeface of the family, Go, is actually serviceable as a coding font.
Typically, proportional fonts such as Times or Helvetica suck as coding fonts, but Go makes all characters distinguishable.
If you want to try something different, you may want to try coding with a proportional font.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
    &lt;th&gt;Homepage&lt;/th&gt;
    &lt;td&gt;&lt;a href=&#34;https://blog.golang.org/go-fonts&#34;&gt;https://blog.golang.org/go-fonts&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;License&lt;/th&gt;
    &lt;td&gt;BSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Glyph count&lt;/th&gt;
    &lt;td&gt;661&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Weights&lt;/th&gt;
    &lt;td&gt;Regular, Bold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Italics?&lt;/th&gt;
    &lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Ligatures?&lt;/th&gt;
    &lt;td&gt;No&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Customizable?&lt;/th&gt;
    &lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&#34;sudo&#34;&gt;Sudo&lt;/h2&gt;
&lt;p&gt;Sudo is the work of one programmer, Jens Kutílek, who decided to create his own coding font in 2009 and is still actively developing it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://vfoley.xyz/font-screenshots/sudo.png&#34;&gt;&lt;img src=&#34;https://vfoley.xyz/font-screenshots/sudo.png&#34; alt=&#34;Sudo&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;div class=&#34;small&#34;&gt;(Click on the image to zoom)&lt;/div&gt;&lt;/center&gt;
&lt;p&gt;Sudo is a narrow font, so if you like having two or three side-by-side splits in your text editor, Sudo is a good choice.
All the characters in Sudo are easy to distinguish, and there is a gap between consecutive underscores.
One characteristic of Sudo is the height of digits: they are a bit shorter than capital letters; this helps to further disambiguate, say, the digit one and the letter el.&lt;/p&gt;
&lt;p&gt;Sudo has a variable font download option, i.e., a single font file that contains the regular, bold, and italic glyphs.
This reduces network transfers if you want to use Sudo on your website.&lt;/p&gt;
&lt;p&gt;One thing you&amp;rsquo;ll note about Sudo is that some characters (e.g., the superscript 3 or the lowercase theta) are very pixelated.
This is due to the way the font designer works: he creates a pixel version first, then he draws the curves.
The pixelated characters are the characters he hasn&amp;rsquo;t yet gotten around to drawing.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
    &lt;th&gt;Homepage&lt;/th&gt;
    &lt;td&gt;&lt;a href=&#34;https://www.kutilek.de/sudo-font/&#34;&gt;https://www.kutilek.de/sudo-font/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;License&lt;/th&gt;
    &lt;td&gt;OFL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Glyph count&lt;/th&gt;
    &lt;td&gt;1071&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Weights&lt;/th&gt;
    &lt;td&gt;Regular, Bold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Italics?&lt;/th&gt;
    &lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Ligatures?&lt;/th&gt;
    &lt;td&gt;No&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Customizable?&lt;/th&gt;
    &lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&#34;monoid&#34;&gt;Monoid&lt;/h2&gt;
&lt;p&gt;Like Sudo, Monoid is another coding font that was developed by a programmer, Andreas Larsen.
Monoid&amp;rsquo;s number one goal is extreme readability, especially at smaller font sizes and its look reminds of bit-mapped fonts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://vfoley.xyz/font-screenshots/monoid.png&#34;&gt;&lt;img src=&#34;https://vfoley.xyz/font-screenshots/monoid.png&#34; alt=&#34;Monoid&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;div class=&#34;small&#34;&gt;(Click on the image to zoom. Note: this is my own customized version of Monoid. The characters &lt;tt&gt;01l$&lt;/tt&gt; might look different for you.)&lt;/div&gt;&lt;/center&gt;
&lt;p&gt;All the characters in Monoid are easy to distinguish. While researching Monoid, I learned that they made an effort to distinguish the Cyrillic letter Ze (З) and the number three (3) by giving three a flat-top.
The characters &lt;code&gt;01l$&lt;/code&gt; can be customized before download; you can also adjust the line spacing and the tracking&amp;mdash;the spacing between characters.
Monoid is the only font in this list to feature programming ligatures, and these can be turned off if you don&amp;rsquo;t like them.&lt;/p&gt;
&lt;p&gt;The creator of Monoid &lt;a href=&#34;https://www.youtube.com/watch?v=hdld21mlzbY&#34;&gt;gave a talk&lt;/a&gt; about the language; the audio quality is not great, but you can learn a lot from this presentation.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
    &lt;th&gt;Homepage&lt;/th&gt;
    &lt;td&gt;&lt;a href=&#34;https://larsenwork.com/monoid/&#34;&gt;https://larsenwork.com/monoid/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;License&lt;/th&gt;
    &lt;td&gt;MIT + OFL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Glyph count&lt;/th&gt;
    &lt;td&gt;618&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Weights&lt;/th&gt;
    &lt;td&gt;Regular, Bold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Italics?&lt;/th&gt;
    &lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Ligatures?&lt;/th&gt;
    &lt;td&gt;Yes (optional)&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Customizable?&lt;/th&gt;
    &lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h2 id=&#34;input-mono&#34;&gt;Input Mono&lt;/h2&gt;
&lt;p&gt;The last language in our list is Input Mono, a font for programmers by professional font designer Jonathan David Ross.
Unlike the other fonts in this list, Input Mono is not open source: it is free for private use, but if you wish to use it on your website or in a print publication, you must purchase a license.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://vfoley.xyz/font-screenshots/input.png&#34;&gt;&lt;img src=&#34;https://vfoley.xyz/font-screenshots/input.png&#34; alt=&#34;Input&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;div class=&#34;small&#34;&gt;(Click on the image to zoom. Note: this is my own customized version of Input; the characters &lt;tt&gt;0agil{*}&lt;/tt&gt; might look different for you.)&lt;/div&gt;&lt;/center&gt;
&lt;p&gt;All the characters in Input are easy to distinguish and it comes with Powerline support out of the box.
At the download screen, you can customize Input: you can choose your shape of choice for the characters &lt;code&gt;0agil{*}&lt;/code&gt; and you can increase or decrease the line spacing.&lt;/p&gt;
&lt;p&gt;Input Mono is part of a &lt;strong&gt;massive&lt;/strong&gt; font family.
In addition to the monospaced variant, there is a sans-serif proportional variant and a serif proportional variant.
Though they aren&amp;rsquo;t monospaced, they are designed with programmers in mind.
Then, each of the three variants comes in three widths: regular, narrow, and condensed.
If you&amp;rsquo;d like for Input to be as slim as Sudo, it can.
Finally, each font has seven weights and an associated italic.
Put it all together, and Input has &lt;strong&gt;126&lt;/strong&gt; different fonts for you to choose from.&lt;/p&gt;
&lt;p&gt;Input Mono has been my daily driver for many months, and I only have good things to say about it.
If you want to hear more about Input, you can watch Jonathan David Ross&amp;rsquo;s presentation, &lt;a href=&#34;https://www.youtube.com/watch?v=SzC3qTo0p1k&#34;&gt;Cracking the Code&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
    &lt;th&gt;Homepage&lt;/th&gt;
    &lt;td&gt;&lt;a href=&#34;https://input.fontbureau.com/&#34;&gt;https://input.fontbureau.com/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;License&lt;/th&gt;
    &lt;td&gt;Free for personal use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Glyph count&lt;/th&gt;
    &lt;td&gt;921&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Weights&lt;/th&gt;
    &lt;td&gt;Thin, Extra Light, Light, Regular, Medium, Bold, Black&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Italics?&lt;/th&gt;
    &lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Ligatures?&lt;/th&gt;
    &lt;td&gt;No&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;th&gt;Customizable?&lt;/th&gt;
    &lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</description>
    </item>
    
    <item>
      <title>My quick review of Cascadia Code</title>
      <link>https://vfoley.xyz/cascadia-code/</link>
      <pubDate>Thu, 19 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>https://vfoley.xyz/cascadia-code/</guid>
      <description>&lt;style&gt;
@font-face{
    font-family: cascadiaCode !important;
    src: url(&#34;/Cascadia.ttf&#34;);
}
h1, h2, h3, p, pre, code {
    font-family: cascadiaCode !important;
}
&lt;/style&gt;
&lt;p&gt;On September 18th, 2019, Microsoft released a new typeface for coders, &lt;a href=&#34;https://devblogs.microsoft.com/commandline/cascadia-code/&#34;&gt;Cascadia Code&lt;/a&gt;.
Cascadia was designed for usage inside Microsoft&amp;rsquo;s new Terminal application and inside coding editors like VSCode or Emacs.
Although it is still just one day old, I thought I&amp;rsquo;d give my thoughts on Cascadia.&lt;/p&gt;
&lt;h2 id=&#34;the-good&#34;&gt;The good&lt;/h2&gt;
&lt;p&gt;Microsoft released Cascadia Code under the terms of the SIL Open Font License, a copyleft license for typefaces:
the author gives up all profit from the sale of the font, but all derivatives must abide by the same terms.
This is great as it ensures that the development of Cascadia Code can continue even if Microsoft no longer has the resources to dedicate to the project.
The OFL also allows anyone to freely use the font on their website, in their screencasts, in their Power Point presentations, in their published articles, in their books, etc.&lt;/p&gt;
&lt;p&gt;I think that Cascadia Code looks really good!
When I first used Ubuntu Mono and Fantasque Sans Mono, I was really taken by how whimsical they looked compared to other coding typefaces.
The common coding typefaces &amp;ndash; DejaVu Sans Mono, Menlo, Consolas, Courier &amp;ndash; are all very straight and, dare I say, soulless.
Cascadia Code has the “fun” quality that Ubuntu Mono and Fantasque Sans Mono have.
Maybe we&amp;rsquo;ll look back on Cascadia in a few years and say, “oh, that typeface is &lt;em&gt;so&lt;/em&gt; 2020!”, but for now I think it brings a needed freshness to coding fonts.
Some fonts are easily identifiable by some of their characters; I believe that the &lt;code&gt;f&lt;/code&gt;, the &lt;code&gt;k&lt;/code&gt;, and the &lt;code&gt;4&lt;/code&gt; are going to be how most people will recognize Cascadia Code.&lt;/p&gt;
&lt;p&gt;Cascadia is easy to read at small sizes; even at 10 points, I have an easy time reading.
(Although, for the sake of your eyes, please don&amp;rsquo;t use tiny font sizes!)&lt;/p&gt;
&lt;p&gt;If ligatures are your kind of thing, has a number of them.
I don&amp;rsquo;t use ligatures myself, so I can&amp;rsquo;t comment on their quality versus other contenders like Fira Code or Iosevka.&lt;/p&gt;
&lt;p&gt;In Cascadia Code, the characters that can look similar in regular typefaces are nicely distinct.
For example, here&amp;rsquo;s what the characters that look like the letter “ell” look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iIl1|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just my opinion, but I don&amp;rsquo;t think there is any ambiguity here.
Same with the “oh&amp;rsquo;s”:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;oO0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dot inside the zero makes it clear that it&amp;rsquo;s a numeral and not a letter.&lt;/p&gt;
&lt;h2 id=&#34;the-bad&#34;&gt;The bad&lt;/h2&gt;
&lt;p&gt;Cascadia Code&amp;rsquo;s “bad” is mostly a product of its age.
First, it does not support characters with accents, which is necessary for people who write in a foreign language.
It also misses many glyphs such as dashes, mathematical symbols, and some symbols used in roguelikes.
I&amp;rsquo;m sure that as Cascadia Code ages, more glyphs will be added.&lt;/p&gt;
&lt;p&gt;Another bad aspect of Cascadia that&amp;rsquo;s certainly a product of its young age: it has no bold face nor italics.
It also doesn&amp;rsquo;t have multiple weights like Source Code Pro or Input.
Again, I&amp;rsquo;m sure we just have to be a bit patient.&lt;/p&gt;
&lt;p&gt;It appears to me that in order to contribute to the development of the font I need to use Windows- and MacOS-only tools.
Not an atypical situation, but it chagrins me when an open font project uses tools that lock out people who would like to contribute.
(I think this shows that there is a need for a better open sourced font development ecosystem.)&lt;/p&gt;
&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I used Cascadia Code today at work and for writing this post.
I think it&amp;rsquo;s a nice font, it&amp;rsquo;s easy to read, and I don&amp;rsquo;t mind some of the quirky characters (e.g., f and k)
as much as I thought I would.&lt;/p&gt;
&lt;p&gt;I definitely recommend that you give it a try, and I wish the team developing Cascadia Code all the best.
I can&amp;rsquo;t wait for the release that has support for accented characters!&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Thank you to Stefan Knudsen for reporting a typo.&lt;/i&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Objective font criterias</title>
      <link>https://vfoley.xyz/font-choice/</link>
      <pubDate>Wed, 24 Jul 2019 00:01:20 -0400</pubDate>
      
      <guid>https://vfoley.xyz/font-choice/</guid>
      <description>&lt;!--
MAIN POINTS:

    - The most important criteria when choosing a font: do you like it?
    - But there are other, less subjective criterias that you would do well to keep in mind:
        1. License: do you need to buy a license? Can you use the font freely for personal use? Can you use it for your website or in your book?
        2. Glyph support: does the font support many Unicode glyphs? It could be important if you speak a foreign language or play roguelikes
        3. Weights and styles: Some fonts only have the roman face; do you want/need bold, italic, thinner and/or thicker strokes?
        4. Customization: can you customize the way the font looks?
        5. Active development: can you expect new glyphs to be added, problems to be fixed? Or is the font &#34;done&#34;?
--&gt;
&lt;p&gt;When you choose a font, the most important criteria is “do you like it, and could you stand to look at it for 8 hours per day?”
There&amp;rsquo;s no accounting for taste, so if the short leg of the the letter &lt;code&gt;m&lt;/code&gt; in &lt;a href=&#34;https://en.wikipedia.org/wiki/Ubuntu_(typeface)&#34;&gt;Ubuntu Mono&lt;/a&gt; really bugs you, then you should pick a different font and don&amp;rsquo;t let anyone tell you that you&amp;rsquo;re wrong.
But fonts have characteristics that aren&amp;rsquo;t subjective, and when you&amp;rsquo;re choosing a new font, it makes sense to consider these as well.&lt;/p&gt;
&lt;h2 id=&#34;license&#34;&gt;License&lt;/h2&gt;
&lt;p&gt;Some fonts require that you purchase a license to use them and they might impose limits on how many people can use them.
&lt;a href=&#34;https://www.fsd.it/shop/fonts/pragmatapro/&#34;&gt;PragmataPro&lt;/a&gt; and &lt;a href=&#34;https://practicaltypography.com/triplicate.html&#34;&gt;Triplicate&lt;/a&gt; are such fonts.
Others can be used free of charge for private use&amp;mdash;&lt;a href=&#34;https://input.fontbureau.com/&#34;&gt;Input&lt;/a&gt; for example&amp;mdash;but a license must be purchased if you want to use them on your website or in a print publication.
In the open source community, many fonts use the &lt;a href=&#34;https://en.wikipedia.org/wiki/SIL_Open_Font_License&#34;&gt;SIL Open Font License&lt;/a&gt;.
You can use, modify, and redistribute those fonts freely; derivative work must be licensed under the same terms&amp;mdash;the OFL is a copyleft license&amp;mdash;and the fonts may not be sold.
Fonts licensed under the terms of the OFL include &lt;a href=&#34;https://github.com/belluzj/fantasque-sans&#34;&gt;Fantasque Sans Mono&lt;/a&gt;, &lt;a href=&#34;https://github.com/be5invis/Iosevka/&#34;&gt;Iosevka&lt;/a&gt;, and &lt;a href=&#34;https://levien.com/type/myfonts/inconsolata.html&#34;&gt;Inconsolata&lt;/a&gt;.
You can use these on your blog or in your papers or package them with your applications without worry.&lt;/p&gt;
&lt;h2 id=&#34;unicode-coverage&#34;&gt;Unicode coverage&lt;/h2&gt;
&lt;p&gt;Some fonts like &lt;a href=&#34;https://dejavu-fonts.github.io/&#34;&gt;DejaVu&lt;/a&gt; have extensive Unicode support, and are appropriate for people who write in foreign languages, who write mathematics, or who just want to use emojis.
When fonts don&amp;rsquo;t have good Unicode coverage, some of the unsupported glyphs will be replaced with a blank square, or sometimes a fallback font can be used and that can break the homogeneity of the text.&lt;/p&gt;
&lt;p&gt;If you play roguelikes, some (e.g., &lt;a href=&#34;https://crawl.develz.org/&#34;&gt;Dungeon Crawl: Stone Soup&lt;/a&gt;) use Unicode characters to display dungeon features.
I&amp;rsquo;ve seen glyphs overlap when using some fonts, typically when a symbol is left of a common character.
If this happens to you, try using a different font when playing.&lt;/p&gt;
&lt;h2 id=&#34;weights-and-slants&#34;&gt;Weights and slants&lt;/h2&gt;
&lt;p&gt;Anyone who&amp;rsquo;s used a word processor knows how to make fonts bold and/or italic.
But did you know that not all fonts have bold or italic variants?
Did you know that some fonts have multiple weights, not just bold?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Monaco_(typeface)&#34;&gt;Monaco&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Droid_fonts&#34;&gt;Droid Sans Mono&lt;/a&gt; are example of fonts that just have the regular variant&amp;mdash;they don&amp;rsquo;t have italics or bold.
&lt;a href=&#34;https://github.com/tonsky/FiraCode&#34;&gt;Fira Code&lt;/a&gt; comes in three weights&amp;mdash;light, regular, and bold&amp;mdash;but it has no italics.
Many programmer fonts offer regular, bold, italic, and bold-italic faces:
&lt;a href=&#34;https://github.com/belluzj/fantasque-sans&#34;&gt;Fantasque Sans Mono&lt;/a&gt;, &lt;a href=&#34;https://github.com/andreberg/Meslo-Font&#34;&gt;Meslo&lt;/a&gt;, &lt;a href=&#34;https://en.wikipedia.org/wiki/Consolas&#34;&gt;Consolas&lt;/a&gt;, &lt;a href=&#34;https://levien.com/type/myfonts/inconsolata.html&#34;&gt;Inconsolata&lt;/a&gt;, and many more.
Finally, some fonts offer many different weights going from very thin to very thick.
&lt;a href=&#34;https://input.fontbureau.com/&#34;&gt;Input&lt;/a&gt; and &lt;a href=&#34;https://github.com/be5invis/Iosevka/&#34;&gt;Iosevka&lt;/a&gt; are such fonts.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Most fonts are given to you as-is&amp;mdash;what you see is what you get.
However, some fonts let users customize them.
&lt;a href=&#34;https://github.com/be5invis/Iosevka/&#34;&gt;Iosevka&lt;/a&gt; offers 12 stylistic sets out of the box, and if none are entirely satisfactory, you can modify a TOML file and specify exactly the glyphs that you want.
Before downloading &lt;a href=&#34;https://input.fontbureau.com/&#34;&gt;Input&lt;/a&gt; you can customize the glyph for some characters (g, i, l, 0, *, and the braces).
&lt;a href=&#34;https://github.com/source-foundry/hack&#34;&gt;Hack&lt;/a&gt;, a font based on DejaVu Sans Mono, has a &lt;a href=&#34;https://github.com/source-foundry/alt-hack&#34;&gt;repository&lt;/a&gt; of alternative glyphs; if you don&amp;rsquo;t like some of their glyphs, for example their zero, you can change them to something more classic.&lt;/p&gt;
&lt;h2 id=&#34;active-development&#34;&gt;Active development&lt;/h2&gt;
&lt;p&gt;Some fonts are “done”; they are no longer being developed.
This can be frustrating if you find problems with the font and no one can fix it.
At the time of writing this post, many font projects were in active development:
&lt;a href=&#34;https://github.com/be5invis/Iosevka/&#34;&gt;Iosevka&lt;/a&gt;, &lt;a href=&#34;https://github.com/tonsky/FiraCode&#34;&gt;Fira Code&lt;/a&gt;, &lt;a href=&#34;https://github.com/IBM/plex&#34;&gt;IBM Plex&lt;/a&gt;, and many more.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simple usage of GNU parallel</title>
      <link>https://vfoley.xyz/parallel/</link>
      <pubDate>Sat, 13 Jul 2019 09:48:50 -0400</pubDate>
      
      <guid>https://vfoley.xyz/parallel/</guid>
      <description>&lt;!--
MAIN POINTS:
    - GNU Parallel can be really helpful to make some CLI tasks finish faster
    - GNU Parallel has a confusing interface
    - Two use cases: (1) run one command on multiple inputs, (2) run multiple commands
--&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gnu.org/software/parallel/&#34;&gt;GNU Parallel&lt;/a&gt;&lt;sup&gt;1&lt;/sup&gt; is
a great tool if you want to reduce the running time of a command-line
job.  Last week, I had a job that took 30+ minutes to run
sequentially, but finished in less than two minutes when I ran it with
Parallel on a 40-core machine.&lt;/p&gt;
&lt;p&gt;Unfortunately, GNU Parallel does not have a very intuitive interface
and that&amp;rsquo;s a significant hurdle for people who want to use it.  I&amp;rsquo;ve
been frustrated in the past, and I&amp;rsquo;m sure many of you reading have
too.  In this post, I&amp;rsquo;ll show you how to use GNU Parallel to do two
basic, but very useful tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;em&gt;one&lt;/em&gt; command on &lt;em&gt;multiple inputs&lt;/em&gt; in parallel;&lt;/li&gt;
&lt;li&gt;Run &lt;em&gt;multiple commands&lt;/em&gt; in parallel.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;
&lt;p&gt;To help us in our examples, I have created a directory that contains
the files we&amp;rsquo;ll work with.  Their names and their contents is listed
below.  You can download this directory &lt;a href=&#34;https://vfoley.xyz/parallel-demo.zip&#34;&gt;as a zip
file&lt;/a&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;a.txt:
Avocado

b.txt:
Broccoli

c.txt:
Cauliflower

cmdlist:
du -h a.txt
sha1sum b.txt
tr a-z A-Z &amp;lt;c.txt

filelist:
a.txt
b.txt
c.txt
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;running-one-command-on-multiple-inputs&#34;&gt;Running &lt;em&gt;one&lt;/em&gt; command on &lt;em&gt;multiple inputs&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;There are two ways to pass inputs to a command in GNU Parallel: via
the command-line arguments or via a file (or stdin).&lt;/p&gt;
&lt;p&gt;You tell GNU parallel to take its inputs from the command line with
the &lt;code&gt;:::&lt;/code&gt; operator.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ parallel &amp;#39;sha1sum {}&amp;#39; ::: *.txt
d8bcd7a949a2fb7a3e1740e4c61e52f46b781aea  a.txt
3db0058f7068968d90679ceb2184441c729782b9  b.txt
a9db4a2565b96696b594965ef52a98ebadfcc2b8  c.txt

$ parallel &amp;#39;sha1sum {}&amp;#39; ::: a.txt cmdlist
d8bcd7a949a2fb7a3e1740e4c61e52f46b781aea  a.txt
814ca442838f9aa6ec2c01f5ed90de4620cfa990  cmdlist
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, the command we want to run is sha1sum and the &lt;code&gt;{}&lt;/code&gt;
is a &lt;em&gt;placeholder&lt;/em&gt; that is be replaced by an input when invoking the
command.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;(Note: Readers already familiar with GNU Parallel will see that I am
being overly explicit in these examples.  In the example above, I
didn&amp;rsquo;t need to quote the command; in this particular case, I didn&amp;rsquo;t
even need to use a placeholder.  But to be as clear as possible, I
will avoid the shortcuts in this post.)&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;You tell GNU Parallel to take its inputs from a file with the &lt;code&gt;::::&lt;/code&gt;
operator.  If the filename is &lt;code&gt;-&lt;/code&gt;, GNU Parallel reads from stdin.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ parallel &amp;#39;sha1sum {}&amp;#39; :::: filelist
d8bcd7a949a2fb7a3e1740e4c61e52f46b781aea  a.txt
3db0058f7068968d90679ceb2184441c729782b9  b.txt
a9db4a2565b96696b594965ef52a98ebadfcc2b8  c.txt

$ grep [ac] filelist | parallel &amp;#39;tr a-z A-Z &amp;lt;{}&amp;#39; :::: -
AVOCADO
CAULIFLOWER
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I think you&amp;rsquo;ll find this to be the most useful form of GNU Parallel.
You can build a Unix pipeline using familiar tools&amp;mdash;sed, awk,
grep&amp;mdash;to construct a list of inputs and then pipe them to parallel.&lt;/p&gt;
&lt;h2 id=&#34;running-multiple-commands-in-parallel&#34;&gt;Running &lt;em&gt;multiple commands&lt;/em&gt; in parallel&lt;/h2&gt;
&lt;p&gt;To run multiple commands in parallel, use the placeholder as the
command name.  Like in the previous section, you obtain the command
name from the command-line arguments with the &lt;code&gt;:::&lt;/code&gt; operator and from
a file or stdin with the &lt;code&gt;::::&lt;/code&gt; operator.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ parallel &amp;#39;{}&amp;#39; ::: &amp;#39;du -h a.txt&amp;#39; &amp;#39;rot13 &amp;lt;b.txt&amp;#39;
4.0K        a.txt
Oebppbyv

$ parallel &amp;#39;{} a.txt&amp;#39; ::: sha1sum &amp;#39;du -h&amp;#39; &amp;#39;xxd&amp;#39;
d8bcd7a949a2fb7a3e1740e4c61e52f46b781aea  a.txt
4.0K        a.txt
00000000: 4176 6f63 6164 6f0a                      Avocado.

$ parallel &amp;#39;{}&amp;#39; :::: cmdlist
4.0K	a.txt
3db0058f7068968d90679ceb2184441c729782b9  b.txt
CAULIFLOWER

$ grep [ac].txt$ cmdlist | parallel &amp;#39;{}&amp;#39; :::: -
4.0K	a.txt
CAULIFLOWER
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This was a super simple introduction to GNU Parallel; there are a lot
of features that we didn&amp;rsquo;t cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;composing and permuting the inputs from multiple files&lt;/li&gt;
&lt;li&gt;controlling the number of concurrent jobs&lt;/li&gt;
&lt;li&gt;spreading jobs across multiple machines&lt;/li&gt;
&lt;li&gt;using advanced placeholder functionality&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But now that you have a more firm grasp of the basic concepts, you can
work your way up to this advanced functionality.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Thank you to Simon Symeonidis for proof-reading this article.&lt;/i&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;sup&gt;1&lt;/sup&gt; O. Tange (2011): GNU Parallel - The Command-Line Power
Tool, ;login: The USENIX Magazine, February 2011:42-47.
</description>
    </item>
    
    <item>
      <title>Rust and the values of simplicity and ergonomics</title>
      <link>https://vfoley.xyz/rust-simplicity-ergonomics/</link>
      <pubDate>Sat, 11 May 2019 07:06:47 -0400</pubDate>
      
      <guid>https://vfoley.xyz/rust-simplicity-ergonomics/</guid>
      <description>&lt;!--
MAIN POINTS:

    - Software as a reflection of value
    - Some clear values of Rust: Performance, Safety, Productivity
    - In tension: ergonomics and simplicity
    - Winner: ergonomics
    - Examples:
        - method calls
        - match ergonomics
        - ? operator
    - async: lots of talk about a little syntax, people who value simplicity disappointed

--&gt;
&lt;p&gt;If you&amp;rsquo;ve not seen Bryan Cantrill talk about &lt;a href=&#34;https://www.youtube.com/watch?v=2wZ1pCpJUIM&#34;&gt;software as a reflection of values&lt;/a&gt;, let me give you the gist.
He argues that there are many desirable values that we can demand in our software (e.g., performance, reliability, approachability).
These values, though they are all desirable, are in tension: we can&amp;rsquo;t have them all at the same time.
He also argues that &lt;em&gt;for some people&lt;/em&gt;, some of these values are more important than others and the software they write is a reflection of those core values; these core values are pursued at the expense of other values.&lt;/p&gt;
&lt;p&gt;In the video above, Cantrill gives C as an example: the core values of C are performance, simplicity, interoperability, and portability.
He gives another example, OpenBSD, and how it has just one core value: security.
Now, it&amp;rsquo;s not that the authors of C did not value, say, readability, or that the OpenBSD developers do not value performance &amp;ndash; there are no &amp;ldquo;bad&amp;rdquo; values.
But when values are in tension and a decision needs to be made, the core values will always win (if they didn&amp;rsquo;t they wouldn&amp;rsquo;t be core values).
As an example, he points out that &lt;a href=&#34;https://www.theregister.co.uk/2018/06/20/openbsd_disables_intels_hyperthreading/&#34;&gt;OpenBSD disabled hyper-threading&lt;/a&gt;, because it was insecure: their core value of security won over the value of performance.&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;ve come to really appreciate from Cantrill&amp;rsquo;s thesis is that it offers a way to understand why we are sometimes bothered by some technical decisions, yet cannot offer a strong
technical counter-point.
When that happens, it&amp;rsquo;s typically because our own core values are in conflict with the values of the software we use.&lt;/p&gt;
&lt;p&gt;If you head over to the &lt;a href=&#34;https://www.rust-lang.org/&#34;&gt;Rust&lt;/a&gt; website, you&amp;rsquo;ll see in big bold letters the words Performance, Reliability, and Productivity.
A number of new Rust features in recent years have put those three core values above simplicity, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;match ergonomics&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;?&lt;/code&gt; operator&lt;/li&gt;
&lt;li&gt;non-lexical lifetimes&lt;/li&gt;
&lt;li&gt;async IO&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all these cases, the language was made less simple, but in none of these degraded performance, reliability, or productivity.
Many people, including some of my colleagues, are unhappy with these features and try to find technical reasons for why they are bad.
But the technical arguments don&amp;rsquo;t hold very well.
So the argument against them is typically one of values (even if the person doing the arguing does not realize it).
They go against the value of simplicity, and that ticks off the people for whom simplicity is more important than productivity.
(Or even, for those who argue that simplicity is necessary for productivity.)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Feeling more confident with property-testing</title>
      <link>https://vfoley.xyz/prop-testing/</link>
      <pubDate>Tue, 19 Feb 2019 21:42:32 -0500</pubDate>
      
      <guid>https://vfoley.xyz/prop-testing/</guid>
      <description>&lt;!--
MAIN POINTS:

    - simple problem (individual elements to ranges)
    - some corner cases
    - how to test so that I&#39;m confident that the functions is correct?
--&gt;
&lt;p&gt;For one of my projects at work, I thought I could reduce memory usage
by storing vectors of sorted integers as vectors of ranges.  For
example, the vector &lt;code&gt;[1,3,4,5,10,14,15,16,17,18]&lt;/code&gt; would be represented
by &lt;code&gt;[1, 3..5, 10, 14..18]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(Spoiler: the memory usage was higher because there weren&amp;rsquo;t enough
runs of consecutive numbers to offset the cost of using 8 bytes rather
than 4 bytes for single numbers.)&lt;/p&gt;
&lt;p&gt;I quickly wrote a Rust function to convert a slice of u32s to a vector of ranges.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type Range = (u32, u32);

/// Returns the shortest vector of ranges that covers `xs`.
///
/// The argument `xs` should (1) be sorted, (2) contain no dupes.
/// If `xs` respects (1) and (2), then the following invariant holds:
///     expand(&amp;amp;to_ranges(&amp;amp;xs)) == xs
pub fn to_ranges(xs: &amp;amp;[u32]) -&amp;gt; Vec&amp;lt;Range&amp;gt; {
    let mut v: Vec&amp;lt;Range&amp;gt; = Vec::new();

    if xs.is_empty() {
        return v;
    }

    let mut start_idx = 0;
    for idx in 1 .. xs.len() {
        if xs[idx] != xs[idx-1] + 1 {
            v.push( (xs[start_idx], xs[idx-1]) );
            start_idx = idx;
        }
    }
    v.push( (xs[start_idx], xs[xs.len() - 1]) );
    v.shrink_to_fit();
    return v;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Array indices can be hard to get right, and anything more complex than
a simple &lt;em&gt;for&lt;/em&gt; loop and I start doubting myself and I wonder if
there&amp;rsquo;s a subtlety I&amp;rsquo;ve gotten wrong.  My code seems to work, but I&amp;rsquo;m
afraid that it could blow up at the worst possible time.  I&amp;rsquo;m sure
it&amp;rsquo;s a feeling shared by many programmers.&lt;/p&gt;
&lt;p&gt;To give us more confidence, we write unit tests.  We prepare carefully
crafted inputs and we write down their expected outputs; we pass the
inputs to our function, and we ensure that our predicted outputs match
the actual outputs.  Here&amp;rsquo;s a unit test for &lt;code&gt;to_ranges&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#[test]
fn manual_tests() {
    assert!(to_ranges(&amp;amp;[]).is_empty());
    assert_eq!(vec![(1,1), (3,3), (5,5)], to_ranges(&amp;amp;[1,3,5]));
    assert_eq!(vec![(1,4)], to_ranges(&amp;amp;[1,2,3,4]));
    assert_eq!(
        vec![(1,1), (3,5), (10,10), (14,18)],
        to_ranges(&amp;amp;[1,3,4,5,10,14,15,16,17,18]));
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Is this sufficient?  I don&amp;rsquo;t know.  All the tests pass, but there are
only 4, that&amp;rsquo;s not very much.  Maybe there&amp;rsquo;s a condition that&amp;rsquo;s not
tested here?  Maybe I subconsciously avoided an edge case?  We wanted
to increase our confidence in our code, but we&amp;rsquo;ve only increased our
self-doubt!&lt;/p&gt;
&lt;p&gt;Property testing is just another tool in the testing toolbox, but it&amp;rsquo;s
one that can increase our confidence in our code.  Rather than test a
function in a case-by-case fashion, we instead write properties: we
express relationships that exist between &lt;strong&gt;all&lt;/strong&gt; inputs and their
outputs.  We then let a generator feed hundreds, even thousands of
test cases to our function and verify that our properties hold.&lt;/p&gt;
&lt;p&gt;The property for &lt;code&gt;to_ranges&lt;/code&gt; is given in its doc-comment: if an acceptable
input—a slice of sorted u32s with no duplicates—is given, then we should
be able to &amp;ldquo;expand&amp;rdquo; the output and obtain the input again.  This is a common
pattern in property testing.&lt;/p&gt;
&lt;p&gt;Using the &lt;a href=&#34;https://crates.io/crates/proptest&#34;&gt;proptest&lt;/a&gt; crate, I
create a simple property and I ask the proptest runner to generate
5000 inputs and ensure that the property hold.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;use proptest::prelude::*;
use proptest::test_runner::Config;

pub fn expand(ranges: &amp;amp;[Range]) -&amp;gt; Vec&amp;lt;u32&amp;gt; {
    let mut v: Vec&amp;lt;u32&amp;gt; = Vec::new();
    for (start, end) in ranges {
        v.extend(*start ..= *end);
    }
    return v;
}

proptest! {
    #![proptest_config(Config::with_cases(5000))]
    #[test]
    fn prop_to_ranges(bset in prop::collection::btree_set(any::&amp;lt;u32&amp;gt;(), 0 .. 1000)) {
        let input: Vec&amp;lt;u32&amp;gt; = bset.into_iter().collect();
        let output: Vec&amp;lt;u32&amp;gt; = expand(&amp;amp;to_ranges(&amp;amp;input));
        prop_assert_eq!(&amp;amp;input[..], &amp;amp;output[..]);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(I use the generator for &lt;code&gt;BTreeSet&amp;lt;u32&amp;gt;&lt;/code&gt; to obtain a sorted set of
u32s and then convert to a &lt;code&gt;Vec&amp;lt;u32&amp;gt;&lt;/code&gt;.  I think it&amp;rsquo;s simpler than
generating a vector, sorting it, and de-duplicating it.)&lt;/p&gt;
&lt;p&gt;With not very many lines of code, I&amp;rsquo;m able to greatly increase my confidence
that I didn&amp;rsquo;t mess up the indexes in &lt;code&gt;to_ranges&lt;/code&gt;.  It&amp;rsquo;s still possible that
there&amp;rsquo;s something wrong that my property test missed, but it would be much
less likely that a bug was present in code that was tested 5000 times than
in code that was tested 4 times.&lt;/p&gt;
&lt;p&gt;Property tests are a great addition to your testing toolbox.  A recent
book by Fred Hébert, &lt;a href=&#34;https://pragprog.com/book/fhproper/property-based-testing-with-proper-erlang-and-elixir&#34;&gt;Property-Based Testing with PropEr, Erlang, and
Elixir&lt;/a&gt;,
offers a great and approachable introduction to property testing using
tools for Erlang and Elixir.  Although the book is mostly targeted at
programmers of these two communities, there is enough
language-agnostic advice to make it a good purchase for anyone
interested in using property testing to make their programs more
robust.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>purp, an Emacs theme of few colors</title>
      <link>https://vfoley.xyz/purp/</link>
      <pubDate>Wed, 12 Dec 2018 20:02:15 -0500</pubDate>
      
      <guid>https://vfoley.xyz/purp/</guid>
      <description>&lt;p&gt;A few years ago, &lt;a href=&#34;https://www.reddit.com/r/emacs/comments/3oc7jk/nice_emacs_themes_with_a_limited_number_of_colors/&#34;&gt;I asked on Reddit&lt;/a&gt; whether anyone had recommendations for a theme that used only a few colors.  I found that too many colors&amp;mdash;what many refer to as a Christmas tree&amp;mdash;was not helping me understand code better, but in fact was distracting me.  I also thought that turning off syntax highlighting entirely was too radical a solution.  I wanted a theme that would just highlight a few, well-chosen elements.  Unfortunately, most of the minimal themes that I found were monochrome, which is not what I was looking for.&lt;/p&gt;
&lt;p&gt;So I began working on a &lt;a href=&#34;https://vfoley.xyz/syntax-highlighting/&#34;&gt;theme of few colors&lt;/a&gt; that I&amp;rsquo;ve been using and tweaking for a while now.  I&amp;rsquo;ve finally decided to make it available on &lt;a href=&#34;https://github.com/gnuvince/purp&#34;&gt;Github&lt;/a&gt; and publish it to &lt;a href=&#34;https://melpa.org/#/purp-theme&#34;&gt;MELPA&lt;/a&gt;.  You can install purp by invoking the command &lt;code&gt;M-x package-install RET purp-theme&lt;/code&gt;.  A light version called &lt;code&gt;purp-light&lt;/code&gt; is also included in the package.&lt;/p&gt;
&lt;p&gt;I have not gone and modified the color of every face in every mode, just the ones that I encountered daily in my work.  In programming modes, you&amp;rsquo;ll see the following colors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Purple for function definitions&lt;/li&gt;
&lt;li&gt;Green for comments&lt;/li&gt;
&lt;li&gt;Orange for string literals&lt;/li&gt;
&lt;li&gt;Yellow on red for dangerous stuff (e.g., the &lt;code&gt;unsafe&lt;/code&gt; keyword in Rust)&lt;/li&gt;
&lt;li&gt;White (or black) for everything else&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The colors for function definitions and comments makes them easy to find and the color for strings helps to spot an un-escaped double quote.&lt;/p&gt;
&lt;p&gt;I hope you like purp, there&amp;rsquo;s a lot of work left to be done, including how to not have it activate as soon as it&amp;rsquo;s installed, which is a really bad first impression.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rust 2019</title>
      <link>https://vfoley.xyz/rust-2019/</link>
      <pubDate>Sun, 09 Dec 2018 10:45:57 -0500</pubDate>
      
      <guid>https://vfoley.xyz/rust-2019/</guid>
      <description>&lt;p&gt;(This is my response to the call for &lt;a href=&#34;https://blog.rust-lang.org/2018/12/06/call-for-rust-2019-roadmap-blogposts.html&#34;&gt;Rust 2019 Roadmap blog posts&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;In 2019, there are three areas where I would like to see the Rust community focus its efforts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improved compile times&lt;/li&gt;
&lt;li&gt;A community effort to review crates&lt;/li&gt;
&lt;li&gt;More &amp;ldquo;80% solutions&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;improved-compile-times&#34;&gt;Improved compile times&lt;/h2&gt;
&lt;p&gt;I already wrote about compile times in Rust (see &lt;a href=&#34;https://vfoley.xyz/rust-at-work/&#34;&gt;Rust at Work—Two Paint Points&lt;/a&gt; and &lt;a href=&#34;https://vfoley.xyz/rust-compile-speed-tips/&#34;&gt;How to alleviate the pain of Rust compile times&lt;/a&gt;), and I don&amp;rsquo;t have much more to add.  I just want to re-iterate that this issue is very important and that it should be given the attention it deserves.&lt;/p&gt;
&lt;p&gt;The Rust compiler is much slower than the compilers of some &amp;ldquo;competing languages&amp;rdquo; such as Go, D, or Jai.  As Jonathan Blow put it when he first announced that he was working on a programming language, long compile times are a constant source of &lt;em&gt;friction&lt;/em&gt; for developers: they lengthen the write-test loop and they disrupt the programmer&amp;rsquo;s flow.  The success of Go can partly be attributed to its quick compile times; it compiles fast enough that it feels like an interpreted language.  (Of course, other factors contributed to Go&amp;rsquo;s success&amp;mdash;an extensive standard library, a vibrant ecosystem, a friendly community, great tooling, good performance, etc.)  I want new Rust programmers to not be turned off by Rust&amp;rsquo;s long compile times and I want veteran Rust programmers to iterate more quickly and wait less on &lt;code&gt;rustc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The situation &lt;em&gt;is&lt;/em&gt; improving.  Incremental recompilation has been merged and tools like sccache can speed up compilation in CI.  &lt;a href=&#34;https://blog.mozilla.org/nnethercote/2018/05/17/the-rust-compiler-is-getting-faster/&#34;&gt;Nicholas Nethercote&lt;/a&gt; detailed his experiments in making &lt;code&gt;rustc&lt;/code&gt; faster.  A new, upcoming backend, &lt;a href=&#34;https://github.com/CraneStation/cranelift&#34;&gt;cranelift&lt;/a&gt;, appears to be faster than the current LLVM backend.&lt;/p&gt;
&lt;p&gt;I think most Rust programmers realize that improved compile times would be beneficial to everyone, and I look forward to seeing improvements on that front in 2019.&lt;/p&gt;
&lt;h2 id=&#34;a-community-effort-to-review-crates&#34;&gt;A community effort to review crates&lt;/h2&gt;
&lt;p&gt;Rust would not be used nearly as much if it weren&amp;rsquo;t for Cargo and crates.io.  The rich ecosystem of Rust is what made it go from an interesting programming language project to a tool that many now use in production.  In 2019, I would like to see a code review effort from the Rust community.  The goal of these reviews is to provide answers to two questions for anyone looking for a crate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are the quality crates?&lt;/strong&gt;  What are the best crates for making HTTP requests, for consuming from Kafka, or for manipulating dates?  Are those crates reliable enough for business-critical services?  Should I have concerns about their performance or security?  Is the code easy to understand and modify?  In a nutshell, how does one find quality crates?&lt;/p&gt;
&lt;p&gt;At the moment, we try and decide if a crate is worth checking out based on word-of-mouth, number of downloads, number of GitHub stars, the name of the contributors, etc.  Code reviews would be stronger indicators of quality, because someone actually read the code.  &lt;a href=&#34;crev-reddit&#34;&gt;On Reddit&lt;/a&gt;, Dawid Ciężarkiewicz announced &lt;a href=&#34;https://github.com/dpc/crev&#34;&gt;crev&lt;/a&gt;, a language-agnostic tool for publishing and signing code reviews and forming webs of trust.  A tool like that would be ideal for the crates ecosystem.  At my place of work, we&amp;rsquo;ve reviewed a number of the crates that we use in production, to convince ourselves that they were worth using.  We&amp;rsquo;d love to have a place to share that work with the reset of the community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is this crate compromised?&lt;/strong&gt;  In 2018, we heard a few stories (&lt;a href=&#34;getcookies&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;event-stream&#34;&gt;2&lt;/a&gt;) about malicious packages in NPM, the Node.js package repository.  I don&amp;rsquo;t think I&amp;rsquo;ve heard about any backdoors in a crate yet, but I see nothing that would make such attacks impossible.  (We did have an issue back in October with &lt;a href=&#34;https://blog.rust-lang.org/2018/10/19/Update-on-crates.io-incident.html&#34;&gt;squatting&lt;/a&gt; that actually led to a degradation of service.)&lt;/p&gt;
&lt;p&gt;These attacks will undoubtedly become more common in the coming years.  Some aspects of Cargo make these attacks more difficult: the immutability of crates and the ability to pin dependencies at a particular version (ideally, a versio that has been reviewed).  Active code reviews would provide an extra line of defense against these attacks.  They would also, hopefully, increase the overall quality of the most popular crates.&lt;/p&gt;
&lt;h2 id=&#34;more-80-solutions&#34;&gt;More &amp;ldquo;80% solutions&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;Improved compile times and code reviews require time and effort, and are not likely to occur overnight.  While we wait, I&amp;rsquo;d like to see more &amp;ldquo;80% solutions&amp;rdquo;&amp;mdash;projects that perform a task well enough, but without being perfect.  We are lucky to have some incredibly high-quality projects in the Rust ecosystem: serde, hyper, reqwest come to mind.  They are also what I&amp;rsquo;d call 100% solutions: they offer all the features that users could possibly want and they have extremely good performance.  They are also complex beasts, and that makes them more difficult to review.  Some of these projects (e.g., hyper) also have many dependencies, which makes the review process even more difficult, and also increases compile times.&lt;/p&gt;
&lt;p&gt;An example of an 80% project is &lt;a href=&#34;https://github.com/dtolnay/miniserde&#34;&gt;miniserde&lt;/a&gt;: unlike serde, JSON is the only serialization format that miniserde supports, and some Rust datatypes like enums cannot be encoded.  Miniserde has also 10x less code than serde (&lt;a href=&#34;https://github.com/Aaronepower/tokei&#34;&gt;tokei&lt;/a&gt; reports 2379 lines of Rust code for miniserde vs. 25,205 for serde) so it&amp;rsquo;s much easier for a single person to do a full review of the code.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d love to see more such projects: a simple HTTP server for services that just need a &lt;code&gt;/status&lt;/code&gt; endpoint; an HTTP client that can send simple requests and write the responses in a &lt;code&gt;Write&lt;/code&gt; object.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>vi, my favorite config-less editor</title>
      <link>https://vfoley.xyz/vi/</link>
      <pubDate>Fri, 30 Nov 2018 22:14:06 -0500</pubDate>
      
      <guid>https://vfoley.xyz/vi/</guid>
      <description>&lt;!--
MAIN POINTS:

    - used to be a vi user
    - don&#39;t need a config file: super convenient when connecting to a remote
      server at work or shelling into a docker image.
    - I use vi and Emacs very differently: Emacs acts as the central piece of my
      workflow, vi is but one tool in my workflow.
    - I&#39;m not super interested in having functionality inside vi (see :he
      design-not of vim and neovim); I&#39;d prefer when outside tools invoke vi
      (alpine, git, etc.)
--&gt;
&lt;p&gt;Before I became an Emacs user, I was a vi user,
and though Emacs is my primary editor, I still use vi daily.
I use vi for quickly skimming the content of a file and quick edits to configuration files;
I use vi when I&amp;rsquo;m on a remote server or when a command-line utility invokes &lt;code&gt;$EDITOR&lt;/code&gt;.
The main reason why I still use vi is because I&amp;rsquo;m able to use it very efficiently even without a configuration file.&lt;/p&gt;
&lt;p&gt;I learned vi circa 2001 from a magazine and from vimtutor.
It was my primary text editor until 2007 or 2008 when I switched to Emacs.
Back then, I had a rather long &lt;code&gt;.vimrc&lt;/code&gt;, complete with configurations for Linux and Windows, GTK vim and curses vim, and I used a few plugins such as bufexplorer.vim.&lt;/p&gt;
&lt;p&gt;Recently, I deleted my old &lt;code&gt;.vimrc&lt;/code&gt; and started a new one from scratch.
I no longer use plugins and I don&amp;rsquo;t use a GUI version of vim.
For these reasons, I now consider myself more a vi user than a vim user.
(I am however a big fan of text objects, and I want unlimited undo, so using &lt;code&gt;nvi&lt;/code&gt; is not something I would consider.)
My &lt;code&gt;.vimrc&lt;/code&gt; is now only 12 lines and most of these changes are conservative and uncontroversial:
backspace works &amp;ldquo;normally&amp;rdquo; in insert mode all the time, I enable incremental search, I use 4 spaces for indentations rather than hard tabs, I activate syntax highlighting.
Even though vim offers a myriad of settings, a vanilla setup is extremely capable and usable.&lt;/p&gt;
&lt;p&gt;I find that being able to use an editor without custom configuration is extremely useful.
Here are a couple of examples:
I learned how to exploit Linux binaries from the book &lt;a href=&#34;https://nostarch.com/hacking2.htm&#34;&gt;Art of Exploitation&lt;/a&gt;.
The book comes with a companion live CD that you can use to follow examples from the book and try to perform the hacks yourself.
Emacs is not installed in the live CD, but vim is, and I was perfectly happy and comfortable using it to read the source code of the examples and modify them.
Another example: recently at work, I wanted to write a Python script on a server that didn&amp;rsquo;t have Python installed, but had Docker.
I launched a Python container, installed vim-tiny, and proceeded to write, debug, and improve my script without ever feeling that I was editing with a hand tied behind my back.&lt;/p&gt;
&lt;p&gt;It is oddly satisfying to know that no matter the kind of machine I find myself on or the kind of restrictions it has (no network to download Emacs and/or my custom configuration, corporate policy against fetching packages from MELPA, etc.), that there will always be an editor that I can happily use without needing to make it &amp;ldquo;my own&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://web.archive.org/web/20060219132752/http://www.oreilly.com/pub/a/oreilly/ask_tim/1999/unix_editor.html&#34;&gt;Tim O&amp;rsquo;Reilly&lt;/a&gt;
and &lt;a href=&#34;https://www.reddit.com/r/reddit.com/comments/21918/tim_oreilly_editor_vi_or_emacs/c2315/&#34;&gt;Paul Graham&lt;/a&gt;
have also cited usability without configuration a reason for preferring vi to Emacs.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Thanks to &lt;a href=&#34;http://www.rkallos.com/&#34;&gt;Richard Kallos&lt;/a&gt; for proof-reading an early version of this article.&lt;/i&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The evolution of performance in ppbert</title>
      <link>https://vfoley.xyz/ppbert-perf-evolution/</link>
      <pubDate>Wed, 19 Sep 2018 15:58:49 -0400</pubDate>
      
      <guid>https://vfoley.xyz/ppbert-perf-evolution/</guid>
      <description>&lt;p&gt;Today I released &lt;a href=&#34;https://crates.io/crates/ppbert&#34;&gt;ppbert 0.8.4&lt;/a&gt; after I read a comment
on Hacker News that made me leap out of my chair: buffering &lt;code&gt;StdoutLock&lt;/code&gt; improves the performance
of IO-bound programs!  Previously, I thought that doing &lt;code&gt;stdout.lock()&lt;/code&gt; was sufficient.  Oops!&lt;/p&gt;
&lt;p&gt;This release also marks the first time that one of my original test files can be pretty printed in less than a second.
I&amp;rsquo;ll use this occasion to look back on ppbert and how I was able to
improve its performance, little by little.&lt;/p&gt;
&lt;p&gt;As I mentioned &lt;a href=&#34;https://vfoley.xyz/ppbert/&#34;&gt;in a previous post&lt;/a&gt;, I created ppbert because
I needed a tool to inspect the content of the .bert files we use in production, and Erlang
was just too slow for that purpose.  There were two files that were of particular interest
to me; in this post, I&amp;rsquo;ll just call them FileA and FileB.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FileA is 11 MiB in size, and is the most important .bert file in our production system.
If something seems off, it is the first place where I want to go look.
On my laptop, Erlang takes &lt;strong&gt;9 secs&lt;/strong&gt; to parse and pretty print FileA.&lt;/li&gt;
&lt;li&gt;FileB is 96 MiB in size and it was the largest file .bert file we had at the time.
On my laptop, Erlang takes &lt;strong&gt;50 secs&lt;/strong&gt; to parse and pretty print FileB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;pre-historic-times-nom&#34;&gt;Pre-historic times: &lt;code&gt;nom&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Every quarter at work, we reserve one Friday to work on open source projects.
I started ppbert during one of those Open Source Fridays, and I used &lt;code&gt;nom&lt;/code&gt; to get moving quickly.
By the end of the day, I had my first working prototype, and I was very excited:
my new prototype was faster than Erlang!
I don&amp;rsquo;t have time measurements from back then; my current laptop processes FileA in &lt;strong&gt;2.63 secs&lt;/strong&gt; and FileB in &lt;strong&gt;15.60 secs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Over time, though, I grew disenchanted with &lt;code&gt;nom&lt;/code&gt;.
I had difficulty using its macros, and it was difficult to have my own custom errors, so I decided to write my own parser.
(N.B.: this was with nom 2; I have not tried nom 3.)&lt;/p&gt;
&lt;h1 id=&#34;the-first-tagged-releases&#34;&gt;The first tagged releases&lt;/h1&gt;
&lt;p&gt;After a bit of work on my own hand-written parser — not very hard and surprisingly fun for me —
I was able to parse and pretty-print again.
This is when I started turning my attention to performance.
I was happy that I was faster than Erlang, and I was already using ppbert daily at work.
Still, I thought it should be possible with Rust to improve the performance of ppbert further.
I thought that might make the tool more useful to me and others.
(I strongly believe that performance is an enabler: if something is fast enough, people
use it more, and they can often use it in new and surprising ways.)&lt;/p&gt;
&lt;p&gt;The first tagged release of ppbert, 0.1.2 in April of 2017, took &lt;strong&gt;1.26 secs&lt;/strong&gt; to process FileA and &lt;strong&gt;5.42 secs&lt;/strong&gt; for FileB.
Before, I was printing directly to stdout; in 0.1.2, I decided to implement the &lt;code&gt;Display&lt;/code&gt;
trait for my AST, &lt;code&gt;BertTerm&lt;/code&gt;.
I was really happy that writing to an in-memory buffer had such a noticeable impact on performance!&lt;/p&gt;
&lt;p&gt;The next performance improvement came 3 weeks later, ahead of the 0.2.3 release.
I noticed that I was computing the indentation string (i.e., a string made of white spaces)
for every element of a list or a tuple.
I moved this computation outside of the loop, along with a few other minor changes
(e.g., using &lt;code&gt;.write_str()&lt;/code&gt; and &lt;code&gt;.write_char()&lt;/code&gt; instead of &lt;code&gt;write!(&amp;quot;{}&amp;quot;, expr)&lt;/code&gt; when
approriate).
The time to process FileA and FileB were now &lt;strong&gt;0.7 secs&lt;/strong&gt; and &lt;strong&gt;3.0 secs&lt;/strong&gt; respectively.&lt;/p&gt;
&lt;p&gt;In June and July, I toyed around with a few micro-optimizations.
If an atom contained only ASCII characters, I skipped the latin-1
validation and called the unsafe &lt;code&gt;String::from_utf8_unchecked()&lt;/code&gt; function.
I also reserved the right amount of memory for the buffers for Strings and Binaries.
Together, these small optimizations brought the times down to &lt;strong&gt;0.69 secs&lt;/strong&gt; and
&lt;strong&gt;2.88 secs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At that point, I was happy with performance, and concentrated mostly on features:
adding support for JSON output, IMO one of the best feature of ppbert when
combined with the amazing &lt;a href=&#34;https://stedolan.github.io/jq/&#34;&gt;jq&lt;/a&gt;; supporting our
new .bert2 format at work; a new command-line tool to convert between .bert and .bert2; improving the user interface; cleaning up the internals; etc.&lt;/p&gt;
&lt;h1 id=&#34;eight-months-pass&#34;&gt;Eight months pass&lt;/h1&gt;
&lt;p&gt;I kept using ppbert daily, and I was really happy with it.
Eventually, I got back to trying to find places where I could improve performance.
In ppbert 0.5.2, released in April 2018, I found that it was faster to write my
String and Binary literals into a &lt;code&gt;String&lt;/code&gt; buffer and send that entire buffer to
&lt;code&gt;.write_str()&lt;/code&gt;.
The time to process FileA stayed pretty much the same at &lt;strong&gt;0.65 secs&lt;/strong&gt;, an improvement of 40 milli-seconds.
However, for FileB, which is larger, the optimization reduced the time needed to pretty print it to &lt;strong&gt;1.77&lt;/strong&gt; seconds, a one second improvement!&lt;/p&gt;
&lt;p&gt;The 0.6.1 release was interesting: I managed to remove a bunch of &lt;code&gt;unsafe&lt;/code&gt; blocks
that I had put in for &amp;ldquo;performance reasons&amp;rdquo;, but without affecting the overall performance.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s where performance had been, until today, when I added this simple line:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;let mut stdout = BufWriter::new(stdout);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, ppbert can process FileA in &lt;strong&gt;0.25 secs&lt;/strong&gt; and FileB in &lt;strong&gt;0.75 secs&lt;/strong&gt;.
I&amp;rsquo;m really happy with the progress that I made and with the way I made progress:
by finding little places where I could improve performance, and slowly making ppbert faster and faster.&lt;/p&gt;
&lt;p&gt;Here is a small chart showing the evolution of ppbert&amp;rsquo;s performance on FileA and FileB:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://vfoley.xyz/images/ppbert-perf.png&#34; alt=&#34;ppbert perf&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&#34;http://rkallos.com/&#34;&gt;Richard Kallos&lt;/a&gt; for proof-reading this article.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to alleviate the pain of Rust compile times</title>
      <link>https://vfoley.xyz/rust-compile-speed-tips/</link>
      <pubDate>Sat, 11 Aug 2018 07:10:12 -0400</pubDate>
      
      <guid>https://vfoley.xyz/rust-compile-speed-tips/</guid>
      <description>&lt;p&gt;A few days ago, I wrote about two &lt;a href=&#34;https://vfoley.xyz/rust-at-work/&#34;&gt;Rust pain points&lt;/a&gt; when using Rust at work.  One of these points were the long compile times.  In this post, I want to share a few tips that can help alleviate that pain.&lt;/p&gt;
&lt;h2 id=&#34;use-cargo-check&#34;&gt;Use &lt;code&gt;cargo check&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We typically use the compiler for two reasons: to verify if the syntax and/or types are correct and to generate a runnable program.  When compiling a program, especially a release build, the majority of the time is spent generating LLVM bytecode and optimizing that bytecode.  If you only want to know whether your 3-line change typechecks, you don&amp;rsquo;t want to wait for the optimizer.&lt;/p&gt;
&lt;p&gt;For this reason, Cargo has a subcommand called &lt;code&gt;check&lt;/code&gt; that only invokes the front-end.  It completes faster than a debug build and much faster than a release build.&lt;/p&gt;
&lt;p&gt;As an example, here are the timing results of &lt;code&gt;cargo check&lt;/code&gt; and &lt;code&gt;cargo build&lt;/code&gt; for my personal project, ppbert.  (The benchmarks are performed by &lt;a href=&#34;https://github.com/sharkdp/hyperfine/&#34;&gt;hyperfine&lt;/a&gt;.)&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Benchmark #1: cargo clean &amp;amp;&amp;amp; cargo check

  Time (mean ± σ):      8.131 s ±  0.424 s    [User: 24.234 s, System: 1.245 s]

  Range (min … max):    7.529 s …  8.845 s

Benchmark #2: cargo clean &amp;amp;&amp;amp; cargo build

  Time (mean ± σ):     16.904 s ±  0.794 s    [User: 52.009 s, System: 2.240 s]

  Range (min … max):   15.728 s … 18.098 s

Benchmark #3: cargo clean &amp;amp;&amp;amp; cargo build --release

  Time (mean ± σ):     48.454 s ±  2.540 s    [User: 145.644 s, System: 3.205 s]

  Range (min … max):   46.229 s … 54.107 s

Summary

  &amp;#39;cargo clean &amp;amp;&amp;amp; cargo check&amp;#39; ran
    2.08x faster than &amp;#39;cargo clean &amp;amp;&amp;amp; cargo build&amp;#39;
    5.96x faster than &amp;#39;cargo clean &amp;amp;&amp;amp; cargo build --release&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From a clean slate, &lt;code&gt;cargo check&lt;/code&gt; is 2x faster than &lt;code&gt;cargo build&lt;/code&gt; and 6x faster than &lt;code&gt;cargo build --release&lt;/code&gt;.  During development, when you just want to check that what you wrote is correct, definitely reach for &lt;code&gt;cargo check&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;use-sccache&#34;&gt;Use &lt;code&gt;sccache&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A co-worker introduced me to &lt;a href=&#34;https://github.com/mozilla/sccache/&#34;&gt;&lt;code&gt;sccache&lt;/code&gt;&lt;/a&gt;, a compilation caching service by Mozilla that is compatible with Rust.  It will cache the build artifacts that Cargo generates, so if you &lt;code&gt;cargo clean&lt;/code&gt; your project or go to work on a second project that shares dependencies with the first one, you won&amp;rsquo;t have to rebuild everything.&lt;/p&gt;
&lt;p&gt;You can install &lt;code&gt;sccache&lt;/code&gt; with Cargo: &lt;code&gt;cargo install sccache&lt;/code&gt;.  To activate &lt;code&gt;sccache&lt;/code&gt;, add the following line to your &lt;code&gt;.bashrc&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;export RUSTC_WRAPPER=sccache
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here are the time differences.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Benchmark #1: cargo clean &amp;amp;&amp;amp; cargo build

  Time (mean ± σ):     15.726 s ±  0.330 s    [User: 50.183 s, System: 2.210 s]

  Range (min … max):   15.148 s … 16.210 s

Benchmark #2: cargo clean &amp;amp;&amp;amp; RUSTC_WRAPPER=sccache cargo build

  Time (mean ± σ):      6.877 s ±  4.665 s    [User: 6.964 s, System: 0.916 s]

  Range (min … max):    5.135 s … 20.136 s

  Warning: The first benchmarking run for this command was
  significantly slower than the rest (20.136 s). This could be caused
  by (filesystem) caches that were not filled until after the first
  run. You should consider using the &amp;#39;--warmup&amp;#39; option to fill those
  caches before the actual benchmark. Alternatively, use the
  &amp;#39;--prepare&amp;#39; option to clear the caches before each timing run.

Summary

  &amp;#39;cargo clean &amp;amp;&amp;amp; RUSTC_WRAPPER=sccache cargo build&amp;#39; ran
    2.29x faster than &amp;#39;cargo clean &amp;amp;&amp;amp; cargo build&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Given the ease of installing and configuring &lt;code&gt;sccache&lt;/code&gt;, I see no reason not to use it and get that 2x speed boost.  One downside of &lt;code&gt;sccache&lt;/code&gt;: it won&amp;rsquo;t make your continuous integration builds faster.  (You could configure &lt;code&gt;sccache&lt;/code&gt; to use an S3 bucket, but I prefer to have completely clean builds from my CI.)&lt;/p&gt;
&lt;h2 id=&#34;avoid-lto&#34;&gt;Avoid LTO&lt;/h2&gt;
&lt;p&gt;LTO is the acronym for link-time optimization.  Compilers build and optimize compilation units individually.  LTO is a mechanism for taking those individually-optimized object files and finding more opportunities for optimization when they are considered as a group.  This is great if you want to have the fastest possible program, but the price you pay are higher compilation times.  In Rust, the compilation unit is the crate; if the heavy computations are all done in your crate, then maybe LTO isn&amp;rsquo;t necessary.&lt;/p&gt;
&lt;p&gt;Here is the difference in execution time of ppbert with and without LTO on a 100 MiB .bert2 file.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Benchmark #1: /tmp/ppbert-without-lto -2 /tmp/100m.bert2

  Time (mean ± σ):      1.926 s ±  0.005 s    [User: 1.308 s, System: 0.618 s]

  Range (min … max):    1.921 s …  1.937 s

Benchmark #2: /tmp/ppbert-with-lto -2 /tmp/100m.bert2

  Time (mean ± σ):      1.887 s ±  0.012 s    [User: 1.273 s, System: 0.613 s]

  Range (min … max):    1.867 s …  1.905 s

Summary

  &amp;#39;/tmp/ppbert-with-lto -2 /tmp/100m.bert2&amp;#39; ran
    1.02x faster than &amp;#39;/tmp/ppbert-without-lto -2 /tmp/100m.bert2&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There is a slight difference (which is why I enable LTO), but let&amp;rsquo;s look at what LTO does to compile times (with sccache enabled):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Benchmark #1: sed -i &amp;#34;s/lto.*/lto=false/&amp;#34; Cargo.toml &amp;amp;&amp;amp; cargo clean &amp;amp;&amp;amp; cargo build --release

  Time (mean ± σ):      5.793 s ±  0.075 s    [User: 11.390 s, System: 0.767 s]

  Range (min … max):    5.693 s …  5.901 s

Benchmark #2: sed -i &amp;#34;s/lto.*/lto=true/&amp;#34; Cargo.toml &amp;amp;&amp;amp; cargo clean &amp;amp;&amp;amp; cargo build --release

  Time (mean ± σ):     18.483 s ±  0.321 s    [User: 34.288 s, System: 1.182 s]

  Range (min … max):   17.971 s … 18.893 s

Summary

  &amp;#39;sed -i &amp;#34;s/lto.*/lto=false/&amp;#34; Cargo.toml &amp;amp;&amp;amp; cargo clean &amp;amp;&amp;amp; cargo build --release&amp;#39; ran
    3.19x faster than &amp;#39;sed -i &amp;#34;s/lto.*/lto=true/&amp;#34; Cargo.toml &amp;amp;&amp;amp; cargo clean &amp;amp;&amp;amp; cargo build --release&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;LTO makes the compilation of ppbert 300% longer for a 2% speed gain at run-time.  If you have a project that you find too long to build, I encourage you to measure the compile times with and without LTO, and the execution speed with and without LTO.  Maybe you&amp;rsquo;ll find (like I did in a project at work) that you don&amp;rsquo;t want to enable LTO.&lt;/p&gt;
&lt;h2 id=&#34;control-your-dependencies&#34;&gt;Control your dependencies&lt;/h2&gt;
&lt;p&gt;Rust has a rich ecosystem, and every day we have access to more quality crates.  This is mostly a blessing, but more crates mean more compilation, and this has a negative effect on your compile times.  Now, don&amp;rsquo;t shun all dependencies and write everything yourself!  Rather, make sure that the crates your bring in pay for themselves.&lt;/p&gt;
&lt;p&gt;One thing that you can do to control dependencies is to examine your depdendencies and see if they have features that you can disable.  For instance, in ppbert I use &lt;a href=&#34;https://clap.rs&#34;&gt;clap&lt;/a&gt; to parse command-line arguments; by default, clap colors its output and offers suggestions when the user makes a spelling mistake.  Some people like these features, but I&amp;rsquo;m not a fan myself.  Fortuately, the authors of clap have made such features optional.  So I am able to deactivate what I don&amp;rsquo;t need, and not pay the compilation price for it.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the dependency tree of clap with default-features enabled, and without.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ rg default-features Cargo.toml &amp;amp;&amp;amp; cargo tree -p clap
33:default-features=true
clap v2.31.2
├── ansi_term v0.11.0
├── atty v0.2.11
│   └── libc v0.2.42
├── bitflags v1.0.3
├── strsim v0.7.0
├── textwrap v0.9.0
│   └── unicode-width v0.1.5
├── unicode-width v0.1.5 (*)
└── vec_map v0.8.1

$ vi Cargo.toml

$ rg default-features Cargo.toml &amp;amp;&amp;amp; cargo tree -p clap
33:default-features=false
clap v2.31.2
├── bitflags v1.0.3
├── textwrap v0.9.0
│   └── unicode-width v0.1.5
└── unicode-width v0.1.5 (*)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So I only need to compile 4 external crates rather than 9.  Many crates make some of their dependencies optional; make sure you only bring in what you really need.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Rust doesn&amp;rsquo;t have the fastest compiler in the world, and that creates friction when writing code.  I&amp;rsquo;m looking forward to improvements on that front more than any other Rust feature.  Fortunately, in the mean time, there are ways to make Rust compile your projects a little faster.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rust at Work—Two Paint Points</title>
      <link>https://vfoley.xyz/rust-at-work/</link>
      <pubDate>Thu, 09 Aug 2018 13:47:12 -0400</pubDate>
      
      <guid>https://vfoley.xyz/rust-at-work/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://blog.rust-lang.org/2018/08/08/survey.htm&#34;&gt;2018 State of Rust Survey&lt;/a&gt; asks the following question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How could we help make Rust more accepted at your company?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We use Rust in three projects at work, and the two primary concerns for people are (1) the crates ecosystem, and (2) compile times.  I gave some details in my answer to the survey, and I want to expand on those two points here.&lt;/p&gt;
&lt;p&gt;The first pain point we have with Rust at work is the crates ecosystem.
We like Cargo and we like that it offers a first-class solution to managing dependencies and building a project.
However, it&amp;rsquo;s difficult—especially for people who are new to Rust—to know which crates are good and which crates should be avoided.
We mostly have to rely on our past experience with different crates—I recommend clap, regex, and rayon, because I&amp;rsquo;ve had a good experience with them, but was I just lucky to avoid their bugs?
The number of downloads or the number of GitHub stars can give an indication of the popularity of a project, but it does not tell if the project has had a complete code review by a third party, if it&amp;rsquo;s been fuzzed, if the authors are using it in production, etc.
It would be a great help to navigating the crates ecosystem if there were badges that projects could obtain when their versions have met levels of quality assurance that go beyond a unit test suite.&lt;/p&gt;
&lt;p&gt;The other pain point of Rust that makes its adoption less attractive are the long compile times.
It&amp;rsquo;s well known that compiling Rust code takes a long time, especially when using the &lt;code&gt;--release&lt;/code&gt; flag for &lt;code&gt;cargo build&lt;/code&gt;.
There are ways to make compilation faster (this will be the subject of an upcoming post) but the bottom line is that iterating in Rust is slower than in many other languages, including compiled languages like C or Java.&lt;/p&gt;
&lt;p&gt;When he announced that he was working on a new programming language, Jonathan Blow said that he wanted to minimize friction in his language, i.e., the difficulty/effort going from an idea to an implementation.
I think Rust&amp;rsquo;s compile times are one of its greatest source of friction.
The memory model of Rust—with lifetimes, shared borrows, mutable borrows, moves, etc.—is a steep curve when learning Rust, but eventually people form their own mental models, and can then write code quickly and safely.
Waiting on the compiler doesn&amp;rsquo;t get shorter because you are more experienced with Rust.
I&amp;rsquo;m following with interest the &lt;a href=&#34;https://blog.mozilla.org/nnethercote/2018/04/30/how-to-speed-up-the-rust-compiler-in-2018/&#34;&gt;efforts&lt;/a&gt; to make &lt;code&gt;rustc&lt;/code&gt; faster, and I hope that 2018 or 2019 will bring improvements on that front.&lt;/p&gt;
&lt;p&gt;There is one point that no one at work disputes though: the Rust language is incredibly well-designed.
The fans of C and low-level imperative programming and the fans of Scala and high-level functional programming find that the Rust core team has made judicious choices in creating a safe, modern, and fast language.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why you should invest in an editor</title>
      <link>https://vfoley.xyz/why-you-should-invest-in-an-editor/</link>
      <pubDate>Thu, 31 May 2018 21:18:50 -0400</pubDate>
      
      <guid>https://vfoley.xyz/why-you-should-invest-in-an-editor/</guid>
      <description>&lt;p&gt;Emacs 26.1 was released this week and I thought I&amp;rsquo;d use the occasion to write a quick post about the main reason why I stick to Emacs: consistency.  Happily, I realized that this reason applies to other text editors as well.&lt;/p&gt;
&lt;p&gt;I use Emacs for programming; whether it&amp;rsquo;s Rust, C, Erlang, Python, or bash scripts, Emacs is the editor I choose.  For any language I use, I have syntax highlighting and automatic indentation, and depending on the major mode, I can get other cool features such as jump-to-def, auto-completion, or REPL integration.&lt;/p&gt;
&lt;p&gt;I use Emacs for writing; for my blog posts in markdown, for my work journal in org-mode, and for my LaTeX documents, Emacs is the tool I reach for.  The usual actions of spell checking a word, formatting a paragraph, jumping from one sentence to the next all work the same no matter the kind of content.&lt;/p&gt;
&lt;p&gt;I also use Emacs for other tasks: I use magit to manage my git repos, I use elfeed to follow RSS feeds, I use twittering-mode to read Twitter.  I can use usual text tools such as searching by regex or &lt;code&gt;M-x occur&lt;/code&gt; if I&amp;rsquo;m looking for something in particular.  The tool doesn&amp;rsquo;t have to provide the functionality, I get it for free from my editor.&lt;/p&gt;
&lt;p&gt;When I&amp;rsquo;m asked why I don&amp;rsquo;t pick specialized tools, my answer is that I enjoy having a consistent experience, no matter the kind of work I&amp;rsquo;m doing.  Emacs gives me that.  My fingers can perform tasks before I&amp;rsquo;ve had time to think about them.  When I used to switch between Emacs and Eclipse (which I used for Java programming), it would take me a few minutes to readjust when I switched from one tool to the other.  Instead, I prefer to use a single tool and not deal with the difficulties of constant context switching.&lt;/p&gt;
&lt;p&gt;I use Emacs, but if you use Vim, Sublime, Visual Studio Code, or any other editor, you can probably relate.  How fun is it to use Vim text objects in code and in config files, how enjoyable is it to have access to Sublime&amp;rsquo;s multi-cursors in your master&amp;rsquo;s thesis as well as in the code of your personal web page?  There is great value in taking the time to learn and master your text editor and using it for as much work as is reasonable.  (Don&amp;rsquo;t be a zealot though: if another tool is clearly better, use it.  Emacs is a terrible web browser, use Firefox or Chrome instead.)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>What&#39;s next for ppbert?</title>
      <link>https://vfoley.xyz/next-for-ppbert/</link>
      <pubDate>Sun, 27 May 2018 12:06:13 -0400</pubDate>
      
      <guid>https://vfoley.xyz/next-for-ppbert/</guid>
      <description>&lt;p&gt;ppbert has improved since the &lt;a href=&#34;https://vfoley.xyz/ppbert/&#34;&gt;last time&lt;/a&gt; I wrote about it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;ve done more work to improve the speed of pretty-printing; the large .bert file that took 3 seconds to process in Februrary now takes 1.5 seconds.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve added binary artifacts to releases — binaries for &lt;em&gt;ppbert&lt;/em&gt; and &lt;em&gt;bert-convert&lt;/em&gt; that are statically-linked against musl.  You should be able to download these and run them on any 64-bit Linux system.  (I inspired myself heavily from the work of my former co-worker, &lt;a href=&#34;https://github.com/sevagh/pq&#34;&gt;Sevag&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve added support for a new type of file, Erlang&amp;rsquo;s internal &lt;a href=&#34;http://erlang.org/doc/man/disk_log.html&#34;&gt;disk_log&lt;/a&gt; format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next feature of ppbert that I have in mind might be the most ambitious yet: support for pretty-printing Erlang records.  In Erlang, a record is stored as a tuple: the first element is the name of the record, and the remaining elements are the values of the fields.  Consider the &lt;code&gt;person&lt;/code&gt; record below.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-record(person, {
    name,
    gender,
    age
}).

#person{name=&amp;#34;Obama&amp;#34;, gender=male, age=56} = {person, &amp;#34;Obama&amp;#34;, male, 56}.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The record expression (&lt;code&gt;#person{ ... }&lt;/code&gt;) and the tuple expression (&lt;code&gt;{person, ...}&lt;/code&gt;) are equivalent.  When &lt;code&gt;term_to_binary/1&lt;/code&gt; converts a record, it returns a binary for a tuple.&lt;/p&gt;
&lt;p&gt;ppbert can parse and pretty-print tuples, so it can handle records without any problem.  However, it would be useful for users to see their records with the field names, rather than the tuple representation.  To support this, I will add a new command-line option to ppbert to read the record declarations in a .erl or .hrl file.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ppbert --record-definitions my_module.erl --record-definitions my_include.hrl ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One guiding principle for this feature is to never require the user to re-create their record declarations.  I want users to point to their existing Erlang files and have ppbert do the hard work.  To support this feature, I will need to write a scanner and parser for Erlang.  The fields of a record declaration have three parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The name of the field (required);&lt;/li&gt;
&lt;li&gt;The default value of the field (optional);&lt;/li&gt;
&lt;li&gt;The type of the field (optional).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is a more complex definition of the &lt;code&gt;person&lt;/code&gt; record from above:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-record(person, {
    name                                 :: string(),
    gender = undefined                   :: undefined | male | female,
    age    = floor(100 * rand:uniform()) :: pos_integer()
}).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The default value of a field can be an arbitrary expression (though there are a few limitations), and that&amp;rsquo;s why I think I need a complete parser.  I can&amp;rsquo;t think of a way to get the name of a record&amp;rsquo;s fields with just a scanner.&lt;/p&gt;
&lt;p&gt;This feature will require a lot of time and effort, but I think it&amp;rsquo;ll be worth it and should make ppbert an even more useful tool for Erlang programmers.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Reflecting on ppbert</title>
      <link>https://vfoley.xyz/ppbert/</link>
      <pubDate>Fri, 09 Feb 2018 19:06:08 -0500</pubDate>
      
      <guid>https://vfoley.xyz/ppbert/</guid>
      <description>&lt;p&gt;I had an itch: I was pretty-printing the &lt;a href=&#34;http://erlang.org/doc/apps/erts/erl_ext_dist.html&#34;&gt;BERT-encoded&lt;/a&gt; terms that we use in a production system at work and it was &lt;em&gt;very&lt;/em&gt; slow.  The Erlang shell took more than two minutes to dump the largest file.  (It took about 0.1 second to read and parse the file; the rest was spent in &lt;code&gt;io:format&lt;/code&gt;.)  I decided to scratch that itch: I wrote &lt;a href=&#34;https://github.com/gnuvince/ppbert&#34;&gt;ppbert&lt;/a&gt;, a command-line utility that reads BERT-encoded values and pretty-prints them.  I&amp;rsquo;ve worked sporadically on ppbert for almost a year now, I use it daily at work, I&amp;rsquo;m happy with it, and I want to write about some of the things I learned during that journey.&lt;/p&gt;
&lt;p&gt;I wanted ppbert to be a good Unix tool.  It was essential that it can read from stdin, write to stdout, and thus can be inserted in a Unix pipeline.  (I&amp;rsquo;m astounded&amp;mdash;and annoyed&amp;mdash;when programs &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; be used in a pipe.)  The interface of ppbert should be familiar to Unix users: it reads from stdin, from files, or from a mix of both with &lt;code&gt;-&lt;/code&gt; acting as the filename for stdin; normal output goes to stdout, diagnostics and errors go to stderr; the format of warnings and errors follows the typical Unix style (&lt;code&gt;ppbert: reason for error&lt;/code&gt;); the return code is 0 on success and 1 on failure; ppbert has a manpage.  The main &amp;ldquo;failure&amp;rdquo; of ppbert as a Unix tool is that it consumes a whole input file before it starts pretty-printing it (a bit like &lt;code&gt;sort(1)&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;I wrote ppbert in Rust because I like the language and because I wanted to use it.  But if you&amp;rsquo;d like to hear technical reasons why choosing Rust made sense, here are a few.  First, I wanted something that would be faster than Erlang and it would&amp;rsquo;ve been counter-productive to reach for Python or Ruby; Rust compiles to native code, uses LLVM to apply thousands of optimizations, and many benchmarks shows that the performance of Rust programs is &lt;a href=&#34;https://benchmarksgame.alioth.debian.org/u64q/which-programs-are-fastest.html&#34;&gt;right up there with C and C++&lt;/a&gt;.  Rust&amp;rsquo;s type system and ownership/borrowing systems are also right up my alley: I suck at programming, I make mistakes with strings and memory in C all the time, and the Rust bondage helps me write better software.  Rust has a very good story for third-party libraries: cargo is an absolute joy to use, and the selection of quality libraries on &lt;a href=&#34;https://crates.io&#34;&gt;crates.io&lt;/a&gt; is growing quickly (more about good libraries later).  I tried to limit the number of dependencies in ppbert&amp;mdash;for example, I don&amp;rsquo;t use serde to pretty-print JSON&amp;mdash;, but I like that complex functionality is a single line in Cargo.toml away.  Finally, the Rust compiler produces statically-linked executable, which makes it easier to use ppbert on remote servers that don&amp;rsquo;t have development tools installed: I just transfer the executable with &lt;code&gt;scp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m happy that I chose Rust: I had a faster pretty-printer the first time that I compiled an executable and with some further tweaks, I was able to improve the speed to a level that I&amp;rsquo;m happy with.  Today, I can pretty-print the large BERT file in 3 seconds rather than 2 minutes.  I got some of the extra performance gains by applying lessons that one can learn from any language: buffering your output&amp;mdash;the &lt;code&gt;File&lt;/code&gt; struct in Rust doesn&amp;rsquo;t buffer by default; finding ways to do less work in the common cases&amp;mdash;in ppbert I got a satisfying speed boost by avoiding UTF-8 validation when all the bytes of an atom&amp;rsquo;s name where in the ASCII range.  I also got some speed boosts by reaching for some of Rust&amp;rsquo;s unsafe functions, for example by using the &lt;code&gt;.get_unchecked()&lt;/code&gt; Vec method when the bound checks had already been performed.  I found that using &lt;code&gt;perf&lt;/code&gt; with Rust is underwhelming; it could tell me in which functions ppbert spent most of its time, but I had to divine the reasons.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m quite happy with the third-party crates that I use.  I started using nom, a parser combinator library, but I found that using its macros was unnatural and injecting my own errors was awkward, so I stopped using it and wrote my own parser instead.  (This was with nom 2; I have not tried the newer nom 3.)  For command-line arguments parsing, I like clap: it&amp;rsquo;s easy to add new options, and easy to consume them.  Rayon blew me away!  I used it in ppbert&amp;rsquo;s sibling program, bert-convert, and simply by using &lt;code&gt;.par_iter()&lt;/code&gt; rather than &lt;code&gt;.iter()&lt;/code&gt;, I made the conversion of all our production .bert files to .bert2 twice as fast.  The crates num and encoding, which I use for bigints and latin-1 support respectively, were easy to use and because they do their jobs without problems, I haven&amp;rsquo;t needed to look at that code in a long time.&lt;/p&gt;
&lt;p&gt;Some people lament the state of Rust&amp;rsquo;s tooling, particularly IDE support.  I&amp;rsquo;m a simple man: I like &lt;a href=&#34;http://vfoley.xyz/syntax-highlighting/&#34;&gt;some syntax highlighting&lt;/a&gt;, automatic indentation, jump-to-definition, and auto-completion.  Emacs, rust-mode, and racer-mode gave me all that.&lt;/p&gt;
&lt;p&gt;One issue I ran into with Rust itself was how the &lt;code&gt;println!()&lt;/code&gt; macro behaves in a pipeline: if a pipe is closed early while printing a long string, println panics.  The code below exhibits the behaviour in a simple program.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/tmp$ cat sample.rs
fn main() {
    let mut buf = String::new();
    for _ in 0 .. 65536 {
        buf.push_str(&amp;#34;foo\n&amp;#34;)
    }
    println!(&amp;#34;{}&amp;#34;, buf);
}

/tmp$ rustc -O sample.rs

/tmp$ ./sample | head -n 1
foo
thread &amp;#39;main&amp;#39; panicked at &amp;#39;failed printing to stdout: Broken pipe (os error 32)&amp;#39;, /checkout/src/libstd/io/stdio.rs:690:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There is an easy fix, and that&amp;rsquo;s to use the &lt;code&gt;writeln!()&lt;/code&gt; macro and to ignore errors.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/tmp$ cat sample.rs
use std::io::{self, Write};

fn main() {
    let mut buf = String::new();
    for _ in 0 .. 65536 {
        buf.push_str(&amp;#34;foo\n&amp;#34;)
    }
    let _ = writeln!(io::stdout(), &amp;#34;{}&amp;#34;, buf);
}

/tmp$ rustc -O sample.rs

/tmp$ ./sample | head -n 1
foo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It&amp;rsquo;s something to be wary of if you write Unix utilities in Rust.&lt;/p&gt;
&lt;p&gt;Ppbert is not a popular program&amp;mdash;I&amp;rsquo;m probably its only user&amp;mdash;because BERT is not a very popular format.  Still, I&amp;rsquo;m happy with the work I did, I&amp;rsquo;m happy that I scratched that itch, and I&amp;rsquo;m happy that ppbert has been a good vehicle for learning about Rust, improving performance, and creating good Unix programs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Quick reflection on first good Dwarf Fortress</title>
      <link>https://vfoley.xyz/reflections-on-df-1/</link>
      <pubDate>Tue, 02 Jan 2018 20:44:17 -0500</pubDate>
      
      <guid>https://vfoley.xyz/reflections-on-df-1/</guid>
      <description>&lt;p&gt;I just retired my first good, semi-successful fort in Dwarf Fortress.  I decided jot down a few comments while the memories are still fresh. My fort, Commonbread, lasted 6+ years, survived 4 goblin sieges, had 150 dwarfs at its peak, and generated more than ☼1.6M in value.&lt;/p&gt;
&lt;h2 id=&#34;main-mistakes&#34;&gt;Main mistakes&lt;/h2&gt;
&lt;p&gt;My two principal mistakes are related: I picked a cold embark location, and I opened my gates to fight a goblin siege during late-autumn.  My 30-dwarfs military had been training for more than a year and was pretty decent: the siege was pushed back with one casualty.  A number of dwarfs were injured during the siege and went to the hospital to get patched up.  Unfortunately, because the brook was frozen, they did not receive any water and 20 of them died of thirst.&lt;/p&gt;
&lt;p&gt;It would have been possible to leave my gates closed and let the siege last for however long.  I could have continued playing, but because of some limitations I imposed on myself (explained later), I decided that their deaths would signal the end of the fort.  After engraving memorial slabs to the fallen dwarfs, I retired Commonbread.&lt;/p&gt;
&lt;h2 id=&#34;small-mistakes&#34;&gt;Small mistakes&lt;/h2&gt;
&lt;p&gt;My fort layout was not optimal: dwarfs had to slowly carry stones across long distances, the stock piles were too general and too far away from related workshops.  It was to be expected because to keep things simple, I challenged myself to keep the entire fort on one Z-level until I had used all the available space.&lt;/p&gt;
&lt;p&gt;Another mistake was distribution of labor.  I should have created a few classes, e.g., &amp;ldquo;farmer&amp;rdquo;, &amp;ldquo;miner&amp;rdquo;, &amp;ldquo;stone worker&amp;rdquo;, &amp;ldquo;wood worker&amp;rdquo;, &amp;ldquo;hauler&amp;rdquo;, &amp;ldquo;military&amp;rdquo;.  This would&amp;rsquo;ve made it easier and faster to temporarily switch dwarfs.  I also learned that some professions, such as fish dissector, small animal dissector, and animal caretaker are practically useless.&lt;/p&gt;
&lt;p&gt;I was also a bit too eager to make wooden spikes in a map that had not many trees; when I had to build beds or barrels, I was often out of wood.&lt;/p&gt;
&lt;h2 id=&#34;lessons-learned&#34;&gt;Lessons learned&lt;/h2&gt;
&lt;p&gt;More than anything, this fort was a great vehicle for learning more about Dwarf Fortress.  I learned how to use burrows to get my dwarfs to safety during a siege.  I learned how to create military squads, how to make them train, how to move them around, and how to attack enemies.  Making wooden spikes and wooden spike balls is a great way to raise money quickly for when the trade caravans come.  A wall and a raised bridge is a great way to keep an army away.  Some industries that seem unimportant at first, like a clothier, seem to become more important as time passes; I had a number of dwarfs unhappy with the crappy old clothes they were wearing.&lt;/p&gt;
&lt;p&gt;Most important lesson (re-learned): Dwarf Fortress is incredibly addictive and immensly fun.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dwarf Fortress and ivy-mode</title>
      <link>https://vfoley.xyz/ivy-df/</link>
      <pubDate>Wed, 29 Nov 2017 19:14:21 -0500</pubDate>
      
      <guid>https://vfoley.xyz/ivy-df/</guid>
      <description>&lt;p&gt;A new version of &lt;a href=&#34;http://www.bay12games.com/dwarves/&#34;&gt;Dwarf Fortress&lt;/a&gt; was released last week, and it was all the incentive I needed to start playing again.  I suck at DF, but I love that game: it savantly combines depth and complete wackiness and the old-school look-and-feel certainly appeals to me.  Yet, I think that the game has (at least) one huge flaw: its menu system makes &lt;code&gt;ed(1)&lt;/code&gt; look positively user-friendly by comparison.&lt;/p&gt;
&lt;p&gt;There are a lot of tasks that one can perform in Dwarf Fortress: select regions to be dug, build all kinds of shops and accessories, manage a militia, etc.  All these tasks are accessed with the keyboard by navigating through menus.  Consider for instance the &lt;em&gt;Build&lt;/em&gt; main menu:&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/images/df-build.png&#34;&gt;
&lt;/center&gt;
&lt;p&gt;A few of the idiosyncracies of this menu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The items are not ordered alphabetically nor grouped into related tasks, so if you are new (or haven&amp;rsquo;t played in a while), you need to read the entire list to find what you want.&lt;/li&gt;
&lt;li&gt;A menu item and its hotkeys don&amp;rsquo;t necessarily match.  For instance, &lt;em&gt;seat&lt;/em&gt; has the shortcut &lt;em&gt;c&lt;/em&gt; (for &lt;em&gt;chair&lt;/em&gt; presumably) and the &lt;em&gt;C&lt;/em&gt; of &lt;em&gt;Wall/Floor/Stairs/Track&lt;/em&gt; is for &lt;em&gt;Construct&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t tell just by looking at it, but some of the items in that menu open sub-menus, e.g., &lt;em&gt;Workshops&lt;/em&gt; and &lt;em&gt;Wall/Floor/Stairs/Track&lt;/em&gt;.  When hunting for a task to perform, you could read all the items in a menu without finding what you&amp;rsquo;re looking for and not having a clue that you were on the right track.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking into those two sub-menus, we see the same idiosyncracies from before: unordered items and unrelated keyboard shortcuts.  Also, why is &lt;em&gt;floor&lt;/em&gt; in a sub-menu, but &lt;em&gt;floor hatch&lt;/em&gt; is in the primary menu?&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;img src=&#34;https://vfoley.xyz/images/df-build-workshop.png&#34;&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src=&#34;https://vfoley.xyz/images/df-build-construct.png&#34;&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;Tarn Adams, the main developer of Dwarf Fortress, has said that he has very little interest in making the menus better as he constantly adds and removes items.  Still I wonder, would it be possible to make the Dwarf Fortress interface better with little development overhead?  I think that &lt;a href=&#34;https://github.com/abo-abo/swiper&#34;&gt;ivy&lt;/a&gt;, a GNU Emacs package, provides an attractive solution to the problem.&lt;/p&gt;
&lt;p&gt;Ivy is a completion and narrowing framework; it replaces Emacs&amp;rsquo; default auto-completion with a system that is much more powerful.  When the user needs to enter an information that can be completed, ivy will show all the possibilites, and the user can navigate this list or type to narrow down the list of possibilities.  For example, here is ivy showing the files managed by git in a project of mine:&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/images/ivy-initial.png&#34;&gt;
&lt;/center&gt;
&lt;p&gt;I can use the up/down and PageUp/PageDown keys to move the selected element.  I can also type in a fragment to narrow down the list:&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/images/ivy-filtered.png&#34;&gt;
&lt;/center&gt;
&lt;p&gt;In the screenshot above, I typed &lt;em&gt;term&lt;/em&gt; and I now have only one result left.  Pressing &lt;em&gt;Enter&lt;/em&gt; will open the file.&lt;/p&gt;
&lt;p&gt;Thanks to ivy&amp;rsquo;s integration with Emacs and with external tools (git, grep, etc.), a user can quickly find and jump to anything they want: a file, a function, a man page, a search string, etc.  This kind of design would work quite well in Dwarf Fortress: rather than searching haphazardly in a menu, the player could open up a small window, enter a substring, and quickly select the action he wants to perform.&lt;/p&gt;
&lt;p&gt;I used ivy to mock what such a system would look like:&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;img src=&#34;https://vfoley.xyz/images/df-build-ivy.png&#34;&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src=&#34;https://vfoley.xyz/images/df-build-ivy-filtered.png&#34;&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;And you know who else thinks this type of interface is a good idea?  Tarn Adams himself.  Indeed, there are some screens in Dwarf Fortress with this exact interface!  The management screen allows the player to efficiently issue orders (e.g., &lt;em&gt;Construct 10 wooden barrels&lt;/em&gt;).  The management screen contains hundreds of tasks—the screenshot below shows what the screen looks like when it is first accessed—and so a filtering interface is ideal.&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/images/df-manager.png&#34;&gt;
&lt;/center&gt;
&lt;p&gt;The management screen after typing &lt;em&gt;wood bar&lt;/em&gt;:&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/images/df-manager-narrow.png&#34;&gt;
&lt;/center&gt;
&lt;p&gt;Tarn Adams probably wants to focus on the magic system (yes!!) and the code of Dwarf Fortress is closed, however the community is dedicated enough that people have created tools to interact with Dwarf Fortress (e.g., Dwarf Therapist) and also improve Dwarf Fortress itself (DFHack).  Perhaps a motivated hacker will attempt to improve the UI by leveraging the search+narrow framework already inside Dwarf Fortress.&lt;/p&gt;
&lt;!--
(setq build-list
      &#39;(&#34;Armor stand&#34;
        &#34;Bed&#34;
        &#34;Seat&#34;
        &#34;Burial receptacle&#34;
        &#34;Door&#34;
        &#34;Floodgate&#34;
        &#34;Floor hatch&#34;
        &#34;Wall grate&#34;
        &#34;Floor grate&#34;
        &#34;Vertical bars&#34;
        &#34;Floor bars&#34;
        &#34;Cabinet&#34;
        &#34;Kennels&#34;
        &#34;Farm plot&#34;
        &#34;Weapon rack&#34;
        &#34;Statue&#34;
        &#34;Slab&#34;
        &#34;Table&#34;
        &#34;Paved road&#34;
        &#34;Dirt road&#34;
        &#34;Bridge&#34;
        &#34;Well&#34;
        &#34;Siege engines&#34;
        &#34;Furnaces&#34;
        &#34;Glass window&#34;
        &#34;Gem window&#34;
        &#34;Trade depot&#34;
        &#34;Machine components&#34;
        &#34;Instrument&#34;
        &#34;Support&#34;
        &#34;Animal trap&#34;
        &#34;Restraint&#34;
        &#34;Cage&#34;
        &#34;Archery target&#34;
        &#34;Traction bench&#34;
        &#34;Nest box&#34;
        &#34;Hive&#34;
        &#34;Bookcase&#34;
        &#34;Workshop / Leather works&#34;
        &#34;Workshop / Quern&#34;
        &#34;Workshop / Millstone&#34;
        &#34;Workshop / Loom&#34;
        &#34;Workshop / Clothier&#39;s shop&#34;
        &#34;Workshop / Bowyer&#39;s workshop&#34;
        &#34;Workshop / Carpenter&#39;s workshop&#34;
        &#34;Workshop / Metalsmith&#39;s forge&#34;
        &#34;Workshop / Jeweler&#39;s workshop&#34;
        &#34;Workshop / Mason&#39;s workshop&#34;
        &#34;Workshop / Butcher&#39;s shop&#34;
        &#34;Workshop / Tanner&#39;s shop&#34;
        &#34;Workshop / Craftsdwarf&#39;s workshop&#34;
        &#34;Workshop / Siege workshop&#34;
        &#34;Workshop / Mechanic&#39;s workshop&#34;
        &#34;Workshop / Still&#34;
        &#34;Workshop / Farmer&#39;s workshop&#34;
        &#34;Workshop / Kitchen&#34;
        &#34;Workshop / Fishery&#34;
        &#34;Workshop / Ashery&#34;
        &#34;Workshop / Dyer&#39;s shop&#34;
        &#34;Workshop / Soap Maker&#39;s workshop&#34;
        &#34;Workshop / Screw press&#34;
        &#34;Construct / Wall&#34;
        &#34;Construct / Floor&#34;
        &#34;Construct / Ramp&#34;
        &#34;Construct / Up stair&#34;
        &#34;Construct / Down stair&#34;
        &#34;Construct / Up+down stair&#34;
        &#34;Construct / Fortification&#34;
        &#34;Construct / Track&#34;
        &#34;Construct / Track stop&#34;))

(ivy-completing-read &#34;Build:&#34; (sort build-list #&#39;(lambda (a b) (string-lessp a b))))
--&gt;
</description>
    </item>
    
    <item>
      <title>What is a Type Error?</title>
      <link>https://vfoley.xyz/what-is-a-type-error/</link>
      <pubDate>Wed, 13 Sep 2017 17:09:48 -0400</pubDate>
      
      <guid>https://vfoley.xyz/what-is-a-type-error/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.reddit.com/r/programming/comments/6zmgn7/static_vs_dynamic_languages_a_literature_review/dmwo1pl/&#34;&gt;The top comment&lt;/a&gt; by /u/staticassert in a Reddit thread on type systems makes an interesting point, one that I made in the past myself: what is a type error?&lt;/p&gt;
&lt;p&gt;I read those types (pun intended) of threads often enough, and one recurring argument often made by people who doubt the benefits of type systems goes like this: &amp;ldquo;I rarely make errors that the type checker would catch; my bugs are logic in nature.&amp;rdquo;  The problem with this statement&amp;mdash;and this is staticassert&amp;rsquo;s point&amp;mdash;is that it&amp;rsquo;s not clear what constitutes a type error.&lt;/p&gt;
&lt;p&gt;Consider the following scenario: reading one line from a text file when the file is opened in write-only mode.  Is this a type error or not?  Let&amp;rsquo;s look at what Python thinks.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;with open(&amp;#34;/etc/passwd&amp;#34;, &amp;#34;w&amp;#34;) as f:
    line = f.readline()
    print(&amp;#34;[{0}]&amp;#34;.format(line))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When we run this program, we obtain the following error at run-time:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Traceback (most recent call last):
  File &amp;#34;ty.py&amp;#34;, line 1, in &amp;lt;module&amp;gt;
    with open(&amp;#34;/etc/passwd&amp;#34;, &amp;#34;w&amp;#34;) as f:
IOError: [Errno 13] Permission denied: &amp;#39;/etc/passwd&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Python has a &lt;code&gt;TypeError&lt;/code&gt; exception, but this is not the one raised here, so clearly this is a logic error, not a type error&amp;mdash;or is it?  Here is the equivalent code in OCaml:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;let () =
  let f = open_out &amp;#34;/etc/passwd&amp;#34; in
  let line = input_line f in
  Printf.printf &amp;#34;[%s]\n&amp;#34; line
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When we try to &lt;em&gt;compile&lt;/em&gt; this code, we get the following type error at compile-time:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;File &amp;#34;ty.ml&amp;#34;, line 3, characters 24-25:
Error: This expression has type out_channel
       but an expression was expected of type in_channel
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So which is it, is reading from a write-only file descriptor a type error or not?  I think the best answer to this question is &amp;ldquo;reading from a write-only descriptor &lt;em&gt;can be made&lt;/em&gt; into a type error.&amp;rdquo;  At the level of the OS, reading from a file descriptor requires the number of a descriptor, a buffer, and a length.  If something goes wrong, such as reading from a write-only descriptor, an error will be generated.  Though that&amp;rsquo;s the reality of the OS, it doesn&amp;rsquo;t have to be the interface that a language presents to its users.&lt;/p&gt;
&lt;p&gt;Here is another example: it&amp;rsquo;s a common error to add numbers of different unit types, e.g., adding feet and meters without a proper conversion.  In F# the &lt;code&gt;float&lt;/code&gt; type can be parameterized by a unit of measure (e.g., &lt;code&gt;float&amp;lt;meter&amp;gt;&lt;/code&gt; vs. &lt;code&gt;float&amp;lt;foot&amp;gt;&lt;/code&gt;) and an attempt to add two values of different type will cause a compilation error.  If we ask the question &amp;ldquo;is adding values of different units a type error or not?&amp;rdquo;, the answer, like in the previous paragraph, is &amp;ldquo;adding values of different units &lt;em&gt;can be made&lt;/em&gt; into a type error.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Discussions on type systems would be more interesting if rather than discussing subjective topics without hard data (e.g., productivity, ease-of-use) we instead looked at how an error of logic can be made into a type error and whether the cost of doing this is low enough that we&amp;rsquo;d want to do it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A Simple Tip to Improve Rust Program Speed</title>
      <link>https://vfoley.xyz/rust-compilation-tip/</link>
      <pubDate>Wed, 06 Sep 2017 18:05:36 -0400</pubDate>
      
      <guid>https://vfoley.xyz/rust-compilation-tip/</guid>
      <description>&lt;p&gt;I am on vacation this week, so I decided to dig out a backtracking &lt;a href=&#34;https://github.com/gnuvince/sudoku-rs&#34;&gt;Sudoku solver&lt;/a&gt; I wrote last summer and see what I could do to improve its performance.  A couple of changes to the data structures and the algorithm yieled an important speed-up.  Previously, I had used a &lt;code&gt;BTreeSet&lt;/code&gt; to store the list of candidates for a cell; I now use a &lt;code&gt;u32&lt;/code&gt; to represent a set of 9 elements.  I used to compute the list of neighbors of a cell everytime it was needed; I now pre-compute the matrix of neighbors and avoid the unnecessary re-computations.  With these changes, solving 1000 normal-difficulty problems went down from 33 seconds to 1.5 second; the time to solve 1000 very hard problems went down from 15 minutes to 40 seconds.&lt;/p&gt;
&lt;p&gt;I wondered if there was a way that I could improve the performance of my code further.  I looked for places in the code where I could avoid vector indexing&amp;mdash;and in doing so, avoid Rust&amp;rsquo;s bounds checking&amp;mdash;but I didn&amp;rsquo;t really feel like changing the way the whole program worked.  Somewhat randomly, I stumbled on a &lt;a href=&#34;https://users.rust-lang.org/t/what-is-the-implementation-of-count-ones/4923&#34;&gt;forum thread&lt;/a&gt; about the implementation of &lt;code&gt;count_ones()&lt;/code&gt; (popcount), and buried in the detailed answer of &lt;em&gt;sorear&lt;/em&gt; is a command-line option to have &lt;code&gt;rustc&lt;/code&gt; select the CPU that LLVM should target.  By compiling my solver for my particular CPU platform (Intel Skylake), the time to solve the normal problems went down to 0.8 second and the time to solve the very hard problems went down to 20 seconds.  Nearly a 2x speed-up by adding an extra flag, not a bad deal!&lt;/p&gt;
&lt;p&gt;You can pass flags to &lt;code&gt;rustc&lt;/code&gt; from Cargo by using the &lt;code&gt;rustc&lt;/code&gt; sub-command and giving your extra arguments after a double-dash.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cargo build --release
   Compiling sudoku v0.1.0 (file:///home/vfoley/prog/rust/sudoku)
    Finished release [optimized + debuginfo] target(s) in 1.66 secs

$ time ./target/release/sudoku &amp;lt;very_hard.txt &amp;gt;/dev/null
real    0m36.542s
user    0m36.530s
sys     0m0.008s

$ cargo rustc --release -- -C target-cpu=skylake
   Compiling sudoku v0.1.0 (file:///home/vfoley/prog/rust/sudoku)
    Finished release [optimized + debuginfo] target(s) in 1.65 secs

$ time ./target/release/sudoku &amp;lt;very_hard.txt &amp;gt;/dev/null
real    0m17.473s
user    0m17.466s
sys     0m0.004s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update: &lt;a href=&#34;https://www.reddit.com/r/rust/comments/6ynm53/a_simple_tip_to_improve_rust_program_speed/dmosgt8/&#34;&gt;&lt;em&gt;est31&lt;/em&gt; on Reddit&lt;/a&gt; mentions that we can replace &lt;code&gt;skylake&lt;/code&gt; with &lt;code&gt;native&lt;/code&gt; to let the backend figure out the appropriate value.&lt;/p&gt;
&lt;p&gt;Update 2: &lt;a href=&#34;https://www.reddit.com/r/rust/comments/6ynm53/a_simple_tip_to_improve_rust_program_speed/dmox7ks/&#34;&gt;&lt;em&gt;Manisheart&lt;/em&gt; on Reddit&lt;/a&gt; notes that it is better to use the &lt;code&gt;RUSTFLAGS=&amp;quot;-C target-cpu=native&amp;quot;&lt;/code&gt; environment variable instead of the &lt;code&gt;rustc&lt;/code&gt; subcommand as it will apply the native compilation to all dependencies and not just the top crate.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My Review of The Talos Principle</title>
      <link>https://vfoley.xyz/the-talos-principle/</link>
      <pubDate>Sun, 03 Sep 2017 14:02:42 -0400</pubDate>
      
      <guid>https://vfoley.xyz/the-talos-principle/</guid>
      <description>&lt;p&gt;Now that I have a slightly more powerful computer, I was finally able to play through &lt;em&gt;The Talos Principle&lt;/em&gt; and its DLC, &lt;em&gt;The Road to Gehenna&lt;/em&gt;.  [Spoilers below]&lt;/p&gt;
&lt;p&gt;The gameplay is mostly about solving problems by using some items.  You have jammers that can open doors, disable bombs and guns; boxes to hold down buttons and to increase the height of an item; connectors that relay a signal from an emitter to receivers and can open doors; fans to elevate yourself or an object; etc.  The game is divided in three worlds (A, B, C), each world is divided into 8 levels, and each level contains 3 to 5 puzzle zones.  You must use the items in each zone to gain access to a sigil, a tetromino shape.  When you have enough of those shapes, you can unlock new items, new zones, etc.&lt;/p&gt;
&lt;p&gt;I really enjoyed how problem solving was introduced&amp;mdash;there is no hand-holding, rather the game gives you simple puzzles to learn how to use an item and gradually increases the difficulty.  Compared to games that give tutorials on every aspect of the gameplay, the process of discovery is satisfying and you feel less overwhelmed.&lt;/p&gt;
&lt;p&gt;The plot of the game was very interesting as well.  We learn through short audio clips, messages, and chat sessions that humanity is doomed.  Global warming was thawed the polar cap and released a virus that affects apes (including humans).  Faced with its extinction, some scientists join at the IAN institute to create the EL project, Eternal Life.  They created an A.I. that would act and think like a human, thus ensuring that even though humans are gone, humanity remains.  The whole game plays in a simulation where a God-like entity, Elohim, tells you to retreive the sigils, but not to escalate the great tower&amp;mdash;and of course, we are definitely going up that tower!  The goal of the simulation is to &amp;ldquo;evolve&amp;rdquo; a machine that can act and think like a human, even with our flaws and inconsistencies.&lt;/p&gt;
&lt;p&gt;The philosophical questions addressed in the game are quite interesting.  What is a person?  What is conciousness?  What is the qualitative difference between a tree, a frog, and a human?  Can a machine be a person?  Can a machine have a conciousness?  Coincidentally, I am currently reading Douglas Hofstaeder&amp;rsquo;s &lt;em&gt;Gödel, Escher, Bach&lt;/em&gt; which addresses such questions.&lt;/p&gt;
&lt;p&gt;I enjoyed &lt;em&gt;The Talos Principle&lt;/em&gt; greatly (I spent 60+ hours playing the game) and I look forward to &lt;em&gt;The Talos Principle 2&lt;/em&gt;.  If you play, I would advise that you refrain from looking up solutions online.  I cheated this way a few times myself, and each time I regretted it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Speedrunning a Compiler</title>
      <link>https://vfoley.xyz/speedrunning-a-compiler/</link>
      <pubDate>Mon, 07 Aug 2017 20:00:00 -0400</pubDate>
      
      <guid>https://vfoley.xyz/speedrunning-a-compiler/</guid>
      <description>&lt;p&gt;At AdGear, the developers typically end their week at &amp;ldquo;Friday Not
Friday&amp;rdquo;, a team activity from 4pm to 5pm.  One person gives a
presentation on any technical subject while the others listen and sip
a beer to wind down before the week-end.&lt;/p&gt;
&lt;p&gt;Last week, I gave a demonstration that I called &amp;ldquo;Speedrunning a
Compiler&amp;rdquo;.  I wanted to show my colleagues the basics of writing a
compiler, and I thought it would be more instructive if they saw code
rather than an abstract flowchart.  Thus, I wrote a compiler for a
very small language that I call &amp;ldquo;Minilang&amp;rdquo;.  We went over the classic
phases of a compiler: scanner, parser, typechecker, and code
generator.  I used Python as my implementation language; the code I
wrote was not pretty and abused Python&amp;rsquo;s flexibility (mutation galore,
dynamic typing, using strings and dicts instead of objects) and I
generated MIPS assembly.&lt;/p&gt;
&lt;p&gt;The resulting program is available on Github:
&lt;a href=&#34;https://github.com/gnuvince/fnf-vfoley/blob/master/compiler/compiler.py&#34;&gt;https://github.com/gnuvince/fnf-vfoley/blob/master/compiler/compiler.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wrote the scanner and parser by hand partly because Minilang is
simple enough, but mostly because I wanted the process of transforming
text into an AST to not be mysterious and hidden behind tools like
flex and bison (or an equivalent in Python, like PLY).  Similarly,
rather than generating C or JavaScript code, I used assembly because
it seems more &amp;ldquo;real&amp;rdquo;: had I generated C, the question of how the code
becomes executable would&amp;rsquo;ve been hidden by gcc or clang.  Generating
assembly code makes the mapping between high-level concepts and
low-level constructs more explicit.  Also, by generating very naïve
assembly&amp;mdash;I basically implemented a stack machine&amp;mdash;I could show
patterns of code that a simple peephole optimizer should recognize and
replace.&lt;/p&gt;
&lt;p&gt;Thanks to a couple practice runs during the week and some copy-pasting
from my completed example, I was able to finish in about 50 minutes
and hopefully to enlighten my colleagues a little bit.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Less intrusive color theme</title>
      <link>https://vfoley.xyz/syntax-highlighting/</link>
      <pubDate>Mon, 17 Apr 2017 12:51:03 -0400</pubDate>
      
      <guid>https://vfoley.xyz/syntax-highlighting/</guid>
      <description>&lt;p&gt;The purpose of syntax highlighting is to draw attention
to certain parts of the code: it helps us to identify when a comment or a
string literal is not properly terminated, when a keyword is misspelled,
or when an escape sequence is invalid.
Lately, I find that editors colorize too many elements and use too
many colors.
(This is a recently-acquired annoyance; maybe age and worse eyesight have something to do with it?)
When every syntactic construct is highlighted, none of them jumps out, and doesn&amp;rsquo;t that
defeat the purpose?&lt;/p&gt;
&lt;p&gt;Take a look at the screenshot of &lt;a href=&#34;http://sublimetext.com&#34;&gt;Sublime Text&lt;/a&gt; below;
I find it difficult to focus on anything, too much is highlighted.&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/syntax-highlighting/sublime.png&#34; alt=&#34;Sublime Text&#34; /&gt;
&lt;/center&gt;
&lt;p&gt;Some programmers have &lt;a href=&#34;https://www.robertmelton.com/2016/04/10/syntax-highlighting-off/&#34;&gt;written&lt;/a&gt;
about turning off syntax highlighting entirely, but this is too extreme for me.
In the &lt;a href=&#34;http://www.ctex.org/documents/shredder/src/texbook.pdf&#34;&gt;TeXBook (p.13)&lt;/a&gt;,
Don Knuth gives this advice to the reader about special typefaces:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Special fonts are effective for emphasis, but not for sustained reading;
your eyes would tire if long portions of this manual were entirely set in
a bold or slanted or italic face.
Therefore roman type accounts for the bulk of most typeset material.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Too many colors&amp;mdash;as is common in programming text editors&amp;mdash;is not ideal,
but neither is a competely barren buffer.
A book that exclusively used Times New Roman 10pt would be extremely difficult to read.
Moderation is key.&lt;/p&gt;
&lt;p&gt;I tried many Emacs themes over the years, and we are lucky to
have a large collection of well-designed themes.
If you don&amp;rsquo;t mind a lot of colors, the &lt;a href=&#34;https://github.com/cpaulik/emacs-material-theme&#34;&gt;material themes&lt;/a&gt; are quite nice.&lt;/p&gt;
&lt;p&gt;However, since I couldn&amp;rsquo;t find one that used only a few colors,
I decided to build my own, &lt;em&gt;Purp&lt;/em&gt;.
It&amp;rsquo;s not too hard to do in Emacs, and there are plenty of
open-source themes that one can use for inspiration and education.
In Purp, I tried to minimize the number of colors
and the number of elements that are highlighted.
You can see the result in the screenshots below.&lt;/p&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/syntax-highlighting/purp2.png&#34; alt=&#34;Purp Theme&#34; /&gt;
&lt;/center&gt;
&lt;center&gt;
&lt;img src=&#34;https://vfoley.xyz/syntax-highlighting/purp3.png&#34; alt=&#34;Purp Theme&#34; /&gt;
&lt;/center&gt;
&lt;p&gt;I consider that the following elements are important enough to have their own color:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;String and character literals: I want to know if they are properly terminated;&lt;/li&gt;
&lt;li&gt;Comments: I want to find them quickly, and in languages that don&amp;rsquo;t have
nested comments, syntax highlighting will show when you made an error;&lt;/li&gt;
&lt;li&gt;Function names: a theme called &lt;a href=&#34;https://draculatheme.com/emacs/&#34;&gt;Dracula&lt;/a&gt; gives
function names a bright color and I find that it helps me identify where
a function begins better than the indentation does, so I stole the idea;&lt;/li&gt;
&lt;li&gt;Pre-processor commands: these are often not subject to the same rules as the base
language and I wanted to see them easily;&lt;/li&gt;
&lt;li&gt;Warnings: some language modes (e.g., Rust) use this face to identify dangerous constructs, so
it&amp;rsquo;s not a bad idea to make sure they are visible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything else uses the default typeface.
I think the code looks much &amp;ldquo;calmer&amp;rdquo; than it did in the Sublime screenshot.&lt;/p&gt;
&lt;p&gt;Purp isn&amp;rsquo;t publicly available yet, because there&amp;rsquo;s still a lot of work left to do.
My installation of Emacs defines 418 faces (org mode has 75), but I&amp;rsquo;ve only
defined colors for 25 of those.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Functional Queues</title>
      <link>https://vfoley.xyz/functional-queues/</link>
      <pubDate>Thu, 13 Apr 2017 20:18:25 -0400</pubDate>
      
      <guid>https://vfoley.xyz/functional-queues/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Queue_(abstract_data_type)&#34;&gt;First-in first-out queues&lt;/a&gt; are a data structure used in many algorithms (including my favorite one&amp;mdash;breadth-first search) and as a building block for complex functionality, the operations on queues should be as efficient as possible.  This can be a bit of a challenge in a functional language: the bread-and-butter data structure of functional programming, the list, supports fast insertion and deletion at the head&amp;mdash;ideal for enqueuing or dequeuing respectively&amp;mdash;but operations at the other end of the list take O(n) time in the length of the list.  Must we give up on our aspirations of purity and use mutable cells?&lt;/p&gt;
&lt;p&gt;Thankfully, a simple and elegant solution to this problem exists.  By using &lt;em&gt;two lists&lt;/em&gt;&amp;mdash;one for enqueuing items and one for dequeuing them&amp;mdash;we can use the fast cons operation to push elements into one list and use pattern matching to pop them out of the other.  If we try to dequeue an element when the pop list is empty and the push list isn&amp;rsquo;t, we reverse the push list, move the elements into the pop list, and continue.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how we can implement this data type.  We will use the OCaml language and we&amp;rsquo;ll start with a signature definition, i.e., the interface that our data type will have to support.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;module type QUEUE = sig
  type &amp;#39;a t
  val empty    : &amp;#39;a t
  val is_empty : &amp;#39;a t -&amp;gt; bool
  val enqueue  : &amp;#39;a -&amp;gt; &amp;#39;a t -&amp;gt; &amp;#39;a t
  val dequeue  : &amp;#39;a t -&amp;gt; (&amp;#39;a option * &amp;#39;a t)
end
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you aren&amp;rsquo;t familiar with OCaml&amp;rsquo;s module system, this declaration says that &lt;code&gt;QUEUE&lt;/code&gt; is a module signature.  A module implements this signature if it defines a type &lt;code&gt;&#39;a t&lt;/code&gt; (&lt;code&gt;t&lt;/code&gt; is the name, &lt;code&gt;&#39;a&lt;/code&gt; is a type parameter; in Java it would be written as &lt;code&gt;T&amp;lt;A&amp;gt;&lt;/code&gt;) and the functions &lt;code&gt;empty&lt;/code&gt;, &lt;code&gt;is_empty&lt;/code&gt;, &lt;code&gt;enqueue&lt;/code&gt;, and &lt;code&gt;dequeue&lt;/code&gt;.  A user will manipulate our queue module through this interface and will never be aware of its implementation.&lt;/p&gt;
&lt;p&gt;We can then define a module called &lt;code&gt;Queue&lt;/code&gt; (it&amp;rsquo;s common in OCaml, but not required, to use all caps to write the signature name and use Pascal-case for the implementation name).&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;module Queue : QUEUE = struct
  type &amp;#39;a t = (&amp;#39;a list * &amp;#39;a list)

  let empty = ([], [])

  let is_empty = function
    | ([], []) -&amp;gt; true
    | (_, _)   -&amp;gt; false

  let enqueue x (pop, push) =
    (pop, x :: push)

  let rec dequeue = function
    | ([], [])      -&amp;gt; (None, empty)
    | (x::xs, push) -&amp;gt; (Some x, (xs, push))
    | ([], push)    -&amp;gt; dequeue (List.rev push, [])
end
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The type &lt;code&gt;&#39;a t&lt;/code&gt; is a tuple of two lists of &lt;code&gt;&#39;a&lt;/code&gt;.  We create an empty queue by returning a tuple containing two empty lists and we verify that a queue is empty by pattern matching on the tuple and asserting that the two elements are the empty list.  Both operations take constant time.&lt;/p&gt;
&lt;p&gt;To enqueue an element, we use the cons operator (&lt;code&gt;::&lt;/code&gt;) to add it to the front of the push list.  This is also a constant time operation.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dequeue&lt;/code&gt; function is the most interesting, and where the &amp;ldquo;magic&amp;rdquo; happens.  If the pop list and the push list are empty, there are no elements to dequeue and we return &lt;code&gt;None&lt;/code&gt;.  If the pop list has an element in its pop list, we remove it from the list and return it.  When only the push queue has elements, we reverse them (to make sure the least recent is at the head), make that the new pop queue and invoke dequeue again.&lt;/p&gt;
&lt;p&gt;Now, this last operation appears to be O(n), but suppose we have &lt;em&gt;n&lt;/em&gt; calls to &lt;code&gt;enqueue&lt;/code&gt; followed by &lt;em&gt;n&lt;/em&gt; calls to &lt;code&gt;dequeue&lt;/code&gt;; the first dequeue takes time proportional to &lt;em&gt;n&lt;/em&gt; (the list reversal), but all subsequent dequeues take constant time.  This makes the operation O(1) amortised which is why it is acceptable in many applications.&lt;/p&gt;
&lt;p&gt;And there you have it, a purely functional FIFO queue!  For more purely functional data structures, please check out &lt;a href=&#34;https://www.amazon.com/Purely-Functional-Structures-Chris-Okasaki/dp/0521663504&#34;&gt;Purely Functional Data Structures&lt;/a&gt; by Chris Okasaki.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Being a T.A.</title>
      <link>https://vfoley.xyz/being-a-ta/</link>
      <pubDate>Fri, 07 Apr 2017 16:01:49 -0400</pubDate>
      
      <guid>https://vfoley.xyz/being-a-ta/</guid>
      <description>&lt;p&gt;Being a teaching assistant is a job that most graduate students are asked&amp;mdash;pressured even&amp;mdash;to do.
During my time at McGill, I was a T.A. three times: twice for the introduction to compiler design class (taught by my adviser), and once for a functional programming class.
It was difficult, time-consuming, and not well paid, yet being a T.A. was the best job I&amp;rsquo;ve ever had.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve had many bad T.A.&amp;rsquo;s when I was an undergrad; absent from the message boards, with a poor understanding of the subject, and confusing in their explanations, they make hard classes more difficult and bad classes unbearable.
I was determined to be better and so I spent &lt;em&gt;way&lt;/em&gt; more time on my duties than the 5 hours per week that the university paid me.
I reviewed the material carefully, I practiced explaining tricky topics, and I attended lectures.&lt;/p&gt;
&lt;p&gt;For the compiler class, my advisor allowed me to design a new term project.
I selected a subset of the Go programming language (which we call Golite), I implemented a reference compiler, I wrote detailed specifications of the syntax and type system, and I prepared slides for class.
This made me very familiar and sympathetic of the difficulties that students encountered.
My fellow lab mates commented that I took the job too seriously, but I believe the results were worth the effort.
Before, the compiler class had 15-16 students per semester; with the new Golite project, enrollment rose to 50!
On a personal level, all the preparation work made me a better programmer, writer, and pedagogue.
The real prize, though, came from my interactions with the students.
Everyone in the class worked really hard on their project, and I was very pleased with the results.
Astute students reported bugs in my reference implementation or inaccuracies in the specification;
I learned Haskell tricks and C tools from kids who, at 20, were smarter than I will ever be;
I received a huge hug from a student who broke in tears when she and I finally fixed a difficult bug in her project;
I became friends with some of the students who frequently came to my office hours;
and I found that nurturing students into capable craftsmen was an important responsability and it made me feel good about myself.&lt;/p&gt;
&lt;p&gt;At the end of the term, students are asked to evaluate the class.
I was so proud that in spite of the class&amp;rsquo;s difficulty and heavy workload they universally thought that the subjet was interesting and well-taught and that the project was fun, challenging, and practical.&lt;/p&gt;
&lt;p&gt;I will leave you with some comments written about me in the students&amp;rsquo; class evaluations.
It&amp;rsquo;s a little &amp;ldquo;braggy&amp;rdquo;, but I was very moved by their kind words&amp;mdash;they made the time, effort, and sweat that I invested worth it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;He is the best teaching assistant I have ever had. If there is an award for being a teaching assistant, give him two of those.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the best TA&amp;rsquo;s of McGill! Always available and willing to help during his office hours.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Best T.A. I&amp;rsquo;ve ever interacted with at McGill (and I&amp;rsquo;ve been here a while&amp;hellip;)! Extremely helpful, quick to answer questions, very knowledgable, and most importantly cares about the students!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Vincent is the most dedicated TA I&amp;rsquo;ve ever seen. Knowledgeable, competent, ready and actually attends lectures. An excellent TA amongst the cesspool of horribles TAs in Mcgill CS.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Journalistic Writing Exercises 1</title>
      <link>https://vfoley.xyz/journalistic-writing-1/</link>
      <pubDate>Mon, 27 Mar 2017 19:47:35 -0400</pubDate>
      
      <guid>https://vfoley.xyz/journalistic-writing-1/</guid>
      <description>&lt;p&gt;I recently purchased &lt;a href=&#34;https://www.amazon.ca/Journalistic-Writing-Building-Skills-Honing-ebook/dp/B003XU66X4/&#34;&gt;Journalistic Writing&lt;/a&gt; by Robert Knight.  I&amp;rsquo;m not a journalist, but I&amp;rsquo;m sure some of his lessons transfer to other areas of non-fiction writing.  At the end of the first chapter, the author presents the reader with a number of sentences that contain unneeded &lt;em&gt;thats&lt;/em&gt;, &lt;em&gt;there is&amp;rsquo;s&lt;/em&gt;, &lt;em&gt;there are&amp;rsquo;s&lt;/em&gt;, etc.; the goal of the exercise is to rewrite the sentences without them.  Here is my attempt.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There were half a dozen vintage airplanes standing in the foreground of the museum.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Half a dozen vintage airplanes stood in the foreground of the museum.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;He said that there was a 13 percent decrease in drunk-driving citations on the state&amp;rsquo;s highways, roads and streets last year, but there was a substantial increase in the number of accidents blamed on drivers&amp;rsquo; cell phone usage.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The number of drunk-driving citations on the state&amp;rsquo;s highways, roads and streets decreased by 13 percent last year, but the number of accidents blamed on drivers&amp;rsquo; cell phone usage increased substantially.&lt;/li&gt;
&lt;li&gt;He said the number of drunk-driving citations on the state&amp;rsquo;s highways, roads and streets decreased by 13 percent last year, while the number of accidents due to cell phone usage increased substantially.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;There was a surgeon working intently on a prone figure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A surgeon was working intently on a prone figure.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The president said that making the country greener is part of his plan to increase jobs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Making the country greener is part of the president&amp;rsquo;s plan to increase jobs.&lt;/li&gt;
&lt;li&gt;The president&amp;rsquo;s plan to increase jobs includes making the country greener.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Around the world there a millions of children that are starving.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Millions of children around the world are starving.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are three things that can happen when you drive through a yellow light, and two of them are bad.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Three things can happen when you drive through a yellow light, two of them are bad.&lt;/li&gt;
&lt;li&gt;Two of the three things that can happen when you drive through a yellow light are bad.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The police officiers said that they had a warrant and they wanted to inspect the house for weapons and drugs, but there was a pit bull preventing them from entering the front door.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The police officers had a warrant and wanted to inspect the house for weapons and drugs, but a pit bull prevented them from entering the front door.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There was Yogi Berra who said that &amp;ldquo;it ain&amp;rsquo;t over &amp;rsquo;til it&amp;rsquo;s over&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yogi Berra said: &amp;ldquo;it ain&amp;rsquo;t over &amp;rsquo;til it&amp;rsquo;s over.&amp;rdquo;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;She quoted her grandfather, who said that &amp;ldquo;many a damned fool went to college.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;ldquo;Many a damned fool went to college,&amp;rdquo; her grandfather used to say.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The ambassador said that she wanted to know why there were not enough limousines waiting for members of the delegation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The ambassador wanted to know why &lt;em&gt;there weren&amp;rsquo;t&lt;/em&gt; enough limousines for the members of the delegation.&lt;/li&gt;
&lt;li&gt;Too few limousines were waiting for members of the delegation and the ambassador wanted to know why.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Libre de Penser</title>
      <link>https://vfoley.xyz/le-devoir/</link>
      <pubDate>Sat, 18 Mar 2017 12:18:58 -0400</pubDate>
      
      <guid>https://vfoley.xyz/le-devoir/</guid>
      <description>&lt;p&gt;En août dernier, j&amp;rsquo;ai utilisé mon premier chèque de paie pour m&amp;rsquo;offrir un abonnement au journal &lt;em&gt;Le Devoir&lt;/em&gt;.  Ça fait maintenant 6 mois que je le lis plus-ou-moins quotidiennement (ces jours-ci, je passe plus de temps à lire sur la situation politique aux États-Unis) et c&amp;rsquo;est un 17$ par mois très bien investi selon moi: je suis mieux informé qu&amp;rsquo;avant et je peux lire sur mon téléphone, dans mon navigateur web, et même avec un lecteur PDF.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;avais jamais auparavant lu un journal à tous les jours.  En tant qu&amp;rsquo;enfant de l&amp;rsquo;Internet, je me tenais informé principalement via Slashdot ou Reddit et en cliquant sur les histoires qui m&amp;rsquo;intéressaient—donc j&amp;rsquo;étais pas si informé que ça, car je laissais de côté les trucs qui m&amp;rsquo;intéressaient moins.  J&amp;rsquo;essaie maintenant de changer mon attitude et de lire même les articles qui traitent de sujets en dehors de mes intérêts.  Il y a beaucoup d&amp;rsquo;histoires mineures qui prennent que 2 ou 3 paragraphes; elles sont rapides à lire, des fois sont très intéressantes, et sont quasiment jamais sur /r/quebec.  Je m&amp;rsquo;efforce de les lire plus souvent.&lt;/p&gt;
&lt;p&gt;Le fait de lire le journal à tous les jours permet aussi de suivre des histoires qui sont en cours.  Par exemple, en septembre l&amp;rsquo;ONE avait prévu tenir des journées d&amp;rsquo;audience au Palais des Congrès de Montréal.  Ces audiences ont été annulées suite à l&amp;rsquo;intervention de manifestants.  Quelques jours plus tard, on apprenait que deux des commissaires de l&amp;rsquo;ONE avaient rencontré Jean Charest alors qu&amp;rsquo;il lobbyait pour TransCanada, le promoteur d&amp;rsquo;Énergie Est.  Le conflit d&amp;rsquo;intérêt était évident, et chaque jour on en apprenait plus sur l&amp;rsquo;histoire, jusqu&amp;rsquo;à ce que les deux commissaires fautifs se récusent.  Quand on peut suivre une histoire de son début jusqu&amp;rsquo;à son dénouement, ça nous engage plus.&lt;/p&gt;
&lt;p&gt;Le Devoir offre plusieurs types d&amp;rsquo;abonnement; j&amp;rsquo;ai choisit l&amp;rsquo;abonnement électronique, car c&amp;rsquo;était le moins dispendieux et j&amp;rsquo;avais pas envie de recevoir un journal papier tous les matins.  Avec mon abonnement j&amp;rsquo;ai accès à une version complète du journal en format PDF.  C&amp;rsquo;est un fac-similé de la version papier et à ma connaissance, Le Devoir est le seul journal qui offre ce produit.  Même des gros noms tels que La Presse, le New York Times, ou le Washington Post n&amp;rsquo;offrent pas un PDF de leur quotidien.  C&amp;rsquo;est dommage, car c&amp;rsquo;est une façon formidable de lire les nouvelles.  D&amp;rsquo;une part, on voit le journal tel qu&amp;rsquo;il est supposé être vu et le contenu ne change pas d&amp;rsquo;heure en heure comme sur le site web ou l&amp;rsquo;application mobile.  D&amp;rsquo;une autre part, ça évite d&amp;rsquo;avoir des tas de papiers journaux à la maison.  Avec un bon lecteur PDF (je recommende &lt;a href=&#34;https://pwmt.org/projects/zathura/&#34;&gt;zathura&lt;/a&gt;), on peut facilement suivre des liens, faire des recherches dans le texte, etc.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;application mobile—j&amp;rsquo;utilise celle sur Android—est aussi très bonne.  On trouve toujours en haut de la page d&amp;rsquo;accueil &amp;ldquo;Quoi surveiller aujourd&amp;rsquo;hui&amp;rdquo;, un résumé en quelques mots de 4 ou 5 événements qui risquent de faire la manchette durant la journée.  On peut &amp;ldquo;swiper&amp;rdquo; pour passer de nouvelle en nouvelle.  On peut bien sûr configurer la grosseur des polices, activer des alertes courriel une nouvelle d&amp;rsquo;importance est publiée, sélectionner les sujets qui nous intéressent, etc.  L&amp;rsquo;application s&amp;rsquo;intègre bien avec le reste de l&amp;rsquo;environnement: je peux facilement partager un article sur Facebook ou dans Signal, si j&amp;rsquo;ouvre un lien on me demande l&amp;rsquo;application que je veux utiliser (e.g., Le Devoir pour un lien interne, ou Brave pour un lien externe).  L&amp;rsquo;application garde aussi une cache de quelques articles—pratique quand on lit dans le métro.  Petit inconvénient: l&amp;rsquo;application me déconnecte après deux semaines.&lt;/p&gt;
&lt;p&gt;Finalement, l&amp;rsquo;importance du journalisme n&amp;rsquo;a jamais été plus importante qu&amp;rsquo;elle l&amp;rsquo;est maintenant.
Une population informée est absolument nécessaire une démocratie saine.
Les révélations sur les liens étroits entre l&amp;rsquo;administration Trump et la Russie aux États-Unis et
les problèmes de collusion au Québec montrent que les gens au pouvoir testent et dépassent les limites des règles établies.
Le rôle de chien de garde des média n&amp;rsquo;a jamais été aussi primordial.
Pour l&amp;rsquo;équivalent d&amp;rsquo;un trop gros repas chez McDo, je peux supporter nos journalistes et faire ma part pour que les politiciens et les dirigeants d&amp;rsquo;entreprises répondent de leurs actions.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Understanding Recursion</title>
      <link>https://vfoley.xyz/recursion/</link>
      <pubDate>Sat, 11 Mar 2017 22:46:44 -0500</pubDate>
      
      <guid>https://vfoley.xyz/recursion/</guid>
      <description>&lt;p&gt;Recursion is my absolute favorite programming technique.
It&amp;rsquo;s powerful, it&amp;rsquo;s elegant, and for many problems it yields simple and beautiful solutions.
Unfortunately, recursion has a terrible reputation: new programmers find it hard and unnatural and some programmers with years of experience avoid it because of the trauma it incurred when they learned it.
There are valid, practical reasons to not use recursion; fear and disdain are not good reasons.&lt;/p&gt;
&lt;h2 id=&#34;dont-go-down-the-rabbit-hole&#34;&gt;Don&amp;rsquo;t go down the rabbit hole&lt;/h2&gt;
&lt;p&gt;To understand a recursive function, many programmers try to visualize the chain of calls and returns.
The intent is laudable, but this approach inevitably leads to failure.
Humans can only hold 7±2 things in their heads (&lt;a href=&#34;https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two&#34;&gt;Miller&amp;rsquo;s Law&lt;/a&gt;); to properly work out the mechanics of a recursive function, we&amp;rsquo;d have to remember the values of the local variables in every invocation, where recursive calls are made, etc.
Very quickly, our brains would get overloaded, we wouldn&amp;rsquo;t know where we are or where we came from, and we&amp;rsquo;d be no closer to understanding the function.&lt;/p&gt;
&lt;p&gt;The right way to write and understand recursive code is to assume that the function invocations return the right results, and to forget about the mechanics of recursion.
It&amp;rsquo;s easier, faster, and we already do it all the time.
When we invoke &lt;code&gt;f&lt;/code&gt; in &lt;code&gt;main&lt;/code&gt;, do we think about the stack frame of &lt;code&gt;f&lt;/code&gt;?
No!  We rely on the name and/or documentation of the function to know what it does, we use its result, and we move on to the next thing.
Why complicate our lives when we see a call to &lt;code&gt;f&lt;/code&gt; inside &lt;code&gt;f&lt;/code&gt;?
The function call mechanism is the same,  we can just use the result of the function and be on our way.&lt;/p&gt;
&lt;p&gt;The following Python function computes the depth of a tree, i.e., the maximum length between the root node and a leaf node.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;depth&lt;/span&gt;(tree):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; tree &lt;span style=&#34;color:#f92672&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        d_left &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; depth(tree&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;left)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        d_right &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; depth(tree&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;right)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; max(d_left, d_right)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a well-formed recursive function: it has a base case, an inductive case, and the recursive calls are made on &amp;ldquo;smaller&amp;rdquo; inputs, i.e., they are getting closer to the base case.
When the tree is empty (base case), we return zero.
When the tree is not empty (inductive case), we compute the depths of the left and right sub-trees, we take the greatest of those two values, and we add one.
That&amp;rsquo;s it!  We understand this function and we haven&amp;rsquo;t given one iota of thought to stack frames.&lt;/p&gt;
&lt;h2 id=&#34;the-recipe&#34;&gt;The recipe&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Base case:&lt;/strong&gt;
To write a recursive function, we first need to find the base cases.
Most often there is only one, but there may be more.
Typical base cases are: zero, the empty string, the empty list, the empty tree, &lt;code&gt;null&lt;/code&gt;, etc.
If the input to the function is the base case, we return the answer and we&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inductive case:&lt;/strong&gt;
After we&amp;rsquo;ve handled the base cases, it&amp;rsquo;s time to tackle all the other cases.
This is where we do recursive calls.
The argument of a recursive call needs to be &amp;ldquo;smaller&amp;rdquo;&amp;mdash;&amp;ldquo;closer&amp;rdquo; to the base case than the current argument.
If the function accepts an integer and the base case is zero, the typical argument to the recursive call is &lt;code&gt;n-1&lt;/code&gt;; if the function accepts a tree, the typical argument is a sub-tree.
The idea is that eventually a recursive call will hit the base case.
Once you have the result for a smaller input, find how to use it to compute the result of the current input, return it, and you&amp;rsquo;re done.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How &#39;Learning Red Hat Linux&#39; Changed My Life</title>
      <link>https://vfoley.xyz/red-hat-book/</link>
      <pubDate>Sun, 05 Mar 2017 18:00:00 -0500</pubDate>
      
      <guid>https://vfoley.xyz/red-hat-book/</guid>
      <description>&lt;p&gt;Can you point to a book that changed your outlook on life and had a profound impact on the kind of person you are? For me, that book would be &lt;em&gt;Learning Red Hat Linux&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://vfoley.xyz/images/red-hat.jpg&#34; alt=&#34;Learning Red Hat Linux Cover&#34;&gt;&lt;/p&gt;
&lt;p&gt;In 1997, I was 14 and I decided that I wanted to be hacker.  In order to look the part, I wanted to install Linux on my computer.  This was early in Linux&amp;rsquo;s life and the distributions of the time didn&amp;rsquo;t have easy-to-use installers&amp;mdash;we had to create root and boot floppies with a tool called rawrite.exe.  And since I couldn&amp;rsquo;t read English very well back then and knew little about computers, I understood almost nothing that the Slackware 3.4 installation program asked.  I failed to install Linux.  Not a great start for a would-be hacker.&lt;/p&gt;
&lt;p&gt;Fast-forward a couple of years, my English had improved and the installation program of Mandrake 6.1 was easy&amp;mdash;no questions about the size of inodes&amp;mdash;and I managed to get my first Linux desktop up and running!  But now what?  The CD sleeve gave instructions for the installation, but not for going online or manipulating files.&lt;/p&gt;
&lt;p&gt;Somehow, I got my hands on a copy of O&amp;rsquo;Reilly&amp;rsquo;s &lt;em&gt;Learning Red Hat Linux&lt;/em&gt; and the most amazing thing happened to me: as I read, I learned!  During a visit at my grand-parents&amp;rsquo;, I read the chapter that explained how to use &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, and others to manipulate files and directories.  When I got home, I ran to my PC and I was able to use the terminal and the commands I had learned to do meaningful work!  After that, I was hooked: I learned about dozens of classic Unix commands, about the directory layout of Linux, and how to install new software with &lt;code&gt;rpm&lt;/code&gt;.  I even routinely reconfigured and recompiled my own kernel.  At 16 years old, &lt;em&gt;Learning Red Hat Linux&lt;/em&gt; made me realize that reading was the path to understanding, that I could learn any subject by myself if I just took the time to read about it.&lt;/p&gt;
&lt;p&gt;I am 33 years old now, and I still read a lot.  Whenever I want to learn something new, I head over to Amazon.  I learned to play chess, poker, and backgammon from books; the original &lt;em&gt;Programming Ruby&lt;/em&gt; AKA Pickaxe by Thomas and Hunt got me started in programming; these days I read books that give me tips to improve my writing (hopefully they make these articles less painful for you to read); when I got my first girlfriend, I even read &lt;em&gt;A Complete Idiot&amp;rsquo;s Guide to Amazing Sex&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Learning Red Hat Linux&lt;/em&gt; is not a classic like &lt;em&gt;Catcher in the Rye&lt;/em&gt; or &lt;em&gt;How to Make Friends and Influence People&lt;/em&gt;, but its impact on my life has been immediate and lasting and I will be forever grateful for it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Le Processus de Sélection d&#39;un Jury</title>
      <link>https://vfoley.xyz/jury/</link>
      <pubDate>Sun, 26 Feb 2017 08:33:21 -0500</pubDate>
      
      <guid>https://vfoley.xyz/jury/</guid>
      <description>&lt;p&gt;En septembre dernier, j&amp;rsquo;ai reçu une lettre qui me convoquait à la cours de Montréal pour servir comme candidat-juré.  Je ne savais pas du tout comment le processus fonctionnait et quand je suis arrivé au Palais de Justice, j&amp;rsquo;ai réalisé que la majorité des gens présents étaient également ignorants du processus.  J&amp;rsquo;ai pris des notes durant mes deux journées&amp;mdash;que deux, car je n&amp;rsquo;ai pas été retenu comme juré&amp;mdash;que je résume ici et qui, j&amp;rsquo;espère, vous aideront à mieux comprendre cet aspect de notre système judiciaire.&lt;/p&gt;
&lt;p&gt;(Cet article décrit le processus tel qu&amp;rsquo;il s&amp;rsquo;est passé à la Cour Supérieure du Québec; il est possible que les choses se déroulent différement ailleur.)&lt;/p&gt;
&lt;h2 id=&#34;le-déroulement-de-la-journée&#34;&gt;Le déroulement de la journée&lt;/h2&gt;
&lt;p&gt;La chose la plus importante à savoir si vous êtes convoqué est que votre présence est obligatoire.  Si vous ne vous présentez pas, un agent de la cours vous contactera pour connaître la raison de votre absence et vous risquez des représailles.  Soyez au rendez-vous!&lt;/p&gt;
&lt;p&gt;Voici une liste des étapes de la journées.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Confirmation de votre présence:&lt;/strong&gt; à votre arrivée au Palais de Justice, vous (ainsi que des centaines d&amp;rsquo;autres candidats-jurés) présentez votre lettre ainsi qu&amp;rsquo;une pièce d&amp;rsquo;identité pour confirmer votre présence.  On vous donne en retour une attestation de présence et un formulaire qui vous permet d&amp;rsquo;être remboursé pour votre déplacement (6.00$) et votre lunch (14.30$).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accueil:&lt;/strong&gt; le juge entre dans la salle d&amp;rsquo;audience, explique l&amp;rsquo;importance du rôle d&amp;rsquo;un jury dans notre système de justice, et réitère les informations qui se trouvent dans la convocation.  Notamment, il explique les motifs d&amp;rsquo;exemptions.  Certains motifs requièrent qu&amp;rsquo;une personne se récuse: une avocate ou un policier ne sont pas abilité à être jurés, et doivent demander une exemption.  D&amp;rsquo;autres motifs peuvent être utilisés pour demander une exemption: les gens de 65 ans et plus ou les étudiants à temps plein peuvent, s&amp;rsquo;ils le désirent, demander une exemption, mais ce n&amp;rsquo;est pas obligatoire.  &amp;ldquo;Je travaille!&amp;rdquo; n&amp;rsquo;est pas un motif valable d&amp;rsquo;exemption; d&amp;rsquo;ailleurs, il est interdit à votre employeur de vous congédier parce que vous agissez comme juré.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Présentation de la cause:&lt;/strong&gt; le juge présente la cause, résume les chefs d&amp;rsquo;accusation, et lit la liste des avocats et témoins.  Si vous connaissez personnellement une de ces personnes, vous devez obligatoirement demander une exemption.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exemptions:&lt;/strong&gt; le juge se retire dans une autre salle ou il recevera et écoutera les candidats qui croient avoir une raison valable pour obtenir une exemption.  Le processus est long, car des centaines de gens vont demander une exemption.  Pendant ces quelques heures, les autres candidats attendent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sélection du jury:&lt;/strong&gt; une fois que les demandes d&amp;rsquo;exemptions ont été traité, une vingtaine de numéros sont pigés au hasard.  Si le numéro qui figure sur votre convocation sort, vous passez devant le juge et les avocats qui décident s&amp;rsquo;ils vous acceptent dans le jury.  Contrairement à ce que vous avez pu voir à la télé, on vous demande seulement votre nom et votre emploi; vous ne pouvez pas tenter d&amp;rsquo;être refusé en proférant des paroles grossières et racistes.  Si la cause a été médiatisé, on peut vous demander si vous vous souvenez de ses détails.  Si un jury (12 jurés, 2 suppléants) n&amp;rsquo;est pas complet après le premier groupe, un second groupe de 20 est pigé et passe devant le juge et les avocats, et ainsi de suite.  Encore une fois, les candidats qui n&amp;rsquo;ont pas été pigé doivent attendre.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retour le lendemain?:&lt;/strong&gt; une fois qu&amp;rsquo;un jury est formé, le juge revient dans la salle d&amp;rsquo;audience (dans mon cas, il était rendu 16h30) pour en informer les candidats.  Si une autre cause est prête à aller devant jury, les candidats doivent se représenter le lendemain afin de former un autre jury.  Les procédures se déroulent plus rapidement, car il y a beaucoup moins de gens qui peuvent obtenir une exemption.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Libération:&lt;/strong&gt; s&amp;rsquo;il n&amp;rsquo;y a pas d&amp;rsquo;autre cause prête à aller devant jury, le juge vous libère et vous pouvez retourner à vos activités quotidiennes.  Par contre, vous restez à la disposition de la cours jusqu&amp;rsquo;à la fin de la session des assises.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;quoi-faire-quand-on-attend&#34;&gt;Quoi faire quand on attend?&lt;/h2&gt;
&lt;p&gt;La majeure partie de la journée d&amp;rsquo;un candidat-juré est passée à attendre.  Il y a du wi-fi dans le Palais de Justice, mais plutôt que d&amp;rsquo;aller sur Reddit ou Facebook, je vous suggère d&amp;rsquo;utiliser ce temps pour jaser avec d&amp;rsquo;autres candidats-jurés.  Des petits groupes de conversation se forment naturellement, et vous allez certainement rencontrer des gens qui ont des histoires intéressantes à raconter.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai eu l&amp;rsquo;occasion de parler avec un employé de l&amp;rsquo;Hôpital Ste-Justine qui argumentait avec passion pour un Québec indépendant.  J&amp;rsquo;ai rencontré une employée de cafétéria dont la fille voulait devenir sexologue; la famille l&amp;rsquo;agaçait en changeant le poste de la télévision à des chaînes de porno lorsque elle venait au salon.  Une dame en était à sa troisième convocation, mais malgré son désir de siéger comme jurée, elle n&amp;rsquo;avait jamais été retenue.&lt;/p&gt;
&lt;p&gt;Et les gens qui ont déjà servi comme jurés ont tous le même commentaire: malgré les désagréments que cela peut causer, c&amp;rsquo;est une expérience unique, intéressante, et enrichissante.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A month of literate programming</title>
      <link>https://vfoley.xyz/litprog/</link>
      <pubDate>Wed, 22 Feb 2017 14:51:42 -0500</pubDate>
      
      <guid>https://vfoley.xyz/litprog/</guid>
      <description>&lt;p&gt;During the month of December, I completed all the &lt;a href=&#34;http://adventofcode.com/2016&#34;&gt;Advent of Code&lt;/a&gt; problems using a programming technique called Literate Programming (LP).  &lt;a href=&#34;https://github.com/gnuvince/advent-of-code-2016&#34;&gt;My programs&lt;/a&gt; look like LaTeX documents, they mostly contain text that explains the task at hand and details my solution, and they are interspersed with Rust code that gradually builds the solution.  The &lt;code&gt;build.sh&lt;/code&gt; script transforms the LaTeX-like files into PDFs and executables.&lt;/p&gt;
&lt;h2 id=&#34;the-teacher-mindset&#34;&gt;The Teacher Mindset&lt;/h2&gt;
&lt;p&gt;We don&amp;rsquo;t typically write programs with readers in mind.  We may use meaningful identifiers and split code into self-contained logical units, but how many of us leave detailed notes to help the next programmer understand our code?  Beyond clean code considerations, a reader needs to understand the business needs that drive our design, the algorithms that we use, the data structures that underpin those algorithms, the invariants in our code, the system limitations that we must contend with, etc.  The code alone cannot be expected to convey all that information.&lt;/p&gt;
&lt;p&gt;A good literate programmer acts like a teacher.  He presents the problem and the solution in a logical order; he writes his code and his prose carefully; he creates visual aids when they are appropriate; he refers to the literature for more discussion on topics of importance; he fosters understanding.&lt;/p&gt;
&lt;p&gt;A great example of a literate program is  &lt;a href=&#34;http://git.annexia.org/?p=jonesforth.git;a=blob;f=jonesforth.S;h=45e6e854a5d2a4c3f26af264dfce56379d401425;hb=66c56998125f3ac265a3a1df9821fd52cfeee8cc&#34;&gt;JonesForth&lt;/a&gt;, a Forth implementation by &lt;a href=&#34;https://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/&#34;&gt;Richard WM Jones&lt;/a&gt;.  X86 assembler is not an easy language, and the implementation of a programming language can be scary, but the explanations in the comments give the reader all the information he needs to read and understand how the core of a Forth implementation works.  Read the sections on threaded code&amp;mdash;probably the most important sections of the program&amp;mdash;and notice how the author gives us the &amp;ldquo;why&amp;rdquo; (saving memory) and uses clear diagrams to explain the &amp;ldquo;how&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;the-tools-of-lp&#34;&gt;The Tools of LP&lt;/h2&gt;
&lt;p&gt;The mindset described in previous section is the most important ingredient for successful literate programming; if that mindset is achieved, some tools can enhance the end result further.  Some popular LP systems are Don Knuth&amp;rsquo;s WEB and CWEB, and Norman Ramsey&amp;rsquo;s noweb (the tool I used for AoC).  These systems mix a typesetting language (TeX or LaTeX) and a programming language (Pascal and C for WEB and CWEB, any language for noweb).  The tools in these systems can give the author more liberty in the organization of his program and can improve the document that will be read.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;tangler&lt;/em&gt; is the tool that extracts the snippets of code in the document and reorders them in an order that the compiler can digest.  The author of a literate program can use this capability to organize his code in an order that makes pedagogical sense.  It is not limited to top-level declarations either; the tangler works with text, so even individual statements can be reordered if necessary.  For example, the implementation of an algorithm can be presented and discussed before the associated data structures have been defined; or manipulate the content of a file before the file has been opened.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;weaver&lt;/em&gt; is the tool that creates the document that a programmer should read.  A good weaver adds an index, inserts cross-references between the different snippets and functions, and adds syntax coloring to the code.  I recommend reading a literate program in a hammock during the summer for a great time!  &lt;a href=&#34;http://www.ulixos.org/doc/ulix-book-0.13.pdf&#34;&gt;Ulix&lt;/a&gt;, an LP implementation of Unix, shows how beautiful a literate program can look.&lt;/p&gt;
&lt;h2 id=&#34;my-impressions-of-lp&#34;&gt;My Impressions of LP&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s talk about the the aspect of LP that I found the most lacking: the tools.  Doing LP with noweb and Rust is spartan, and I would not recommend writing a large program this way.  Emacs doesn&amp;rsquo;t offer syntax highlighting or auto-indenting for noweb programs, the Racer tool for Rust does not work outside a Cargo projects, and the line numbers given by the compiler do not match the lines in the original source file.&lt;/p&gt;
&lt;p&gt;In spite of the lackluster tools, I enjoyed writing LP solutions for AoC very much.  The overall process was far more difficult than just writing the program itself; I often had difficulty finding the right words to describe the details of my solution, especially when those details were unclear in my head.  The act of writing down my thoughts was often helpful in clarifying my ideas.  It&amp;rsquo;s also a great practice for would-be writers.&lt;/p&gt;
&lt;p&gt;I should also note that if you feel tired, you should probably not write a literate program.  I solved a problem at 11:30 pm and wrote &amp;ldquo;I&amp;rsquo;m really pissed off, so fuck explanations&amp;rdquo;.  It&amp;rsquo;s not a great way to explain how the program works, but it sure is a great reminder that it&amp;rsquo;s always better to go to sleep than to write bad code and bad text.&lt;/p&gt;
&lt;p&gt;I look forward to next November when I re-read the programs and see if I the text I wrote allows me to still understand them.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My Impressions of Final Fantasy IV Advance</title>
      <link>https://vfoley.xyz/ff4-advance/</link>
      <pubDate>Sat, 18 Feb 2017 21:57:13 -0500</pubDate>
      
      <guid>https://vfoley.xyz/ff4-advance/</guid>
      <description>&lt;p&gt;Final Fantasy IV is a fantastic game, and Final Fantasy IV Advance is a fine port plagued by an unforgivable flaw.&lt;/p&gt;
&lt;p&gt;Final Fantasy IV was released in North America as Final Fantasy II; the US port was modified to be an easier game.  Enemies had fewer hit points and the characters had fewer abilities, like Cecil who didn&amp;rsquo;t have his Darkness attack.&lt;/p&gt;
&lt;p&gt;Final Fantasy IV Advance is a port to the GameBoy Advance of Final Fantasy IV as it was in Japan.  It features an improved translation (fans will be happy to know that &amp;ldquo;you spoony bard!&amp;rdquo; was retained), the simple 16-bit graphics are kept as-is, the music is slightly altered because of the different audio hardware, and a number of game-play bugs are fixed (note: play the European version, the US/Australia version has ATB-related bugs).  The game has common quality-of-life features, such as dashing and quick saving.  This version retains the role of the fat Chocobo as an item store; the GBA doesn&amp;rsquo;t lack the memory to store many items that the SNES did, but it&amp;rsquo;s cool that they kept a staple of the original.&lt;/p&gt;
&lt;p&gt;On the surface, FF4A should have been the ultimate way to experience this franchise entry.  Unfortunately, one issue makes playing this game a miserable experience: it has a &lt;strong&gt;ton&lt;/strong&gt; of input lag.&lt;/p&gt;
&lt;p&gt;When navigating the menus or entering actions during battles, players will notice a considerable delay between pressing a button and that command registering.  For example, when healing my party with potions, there was a delay of a whole second between pressing the &lt;code&gt;A&lt;/code&gt; button and the actual healing!  But if this lag is annoying in the menu, it can be enraging during battle.  Often, an input will be entirely discarded, and when that happens, a careless player may do an incorrect action (e.g., targetting a single enemy with magic rather than the whole formation, or selecting the wrong spell to cast.)  The lag happens in both the menu and in battles (which account for the majority of game-play time) and this will certainly test the player&amp;rsquo;s nerves.  I don&amp;rsquo;t understand how Square Enix&amp;rsquo;s QA could have missed such an obvious defect?  And if they didn&amp;rsquo;t miss it, why was the game allowed to be released?&lt;/p&gt;
&lt;p&gt;If you haven&amp;rsquo;t played Final Fantasy IV, try this version for 10-15 minutes; if you aren&amp;rsquo;t too annoyed with the input lag, then keep going, otherwise I recommend trying a fan translation ROM for the SNES.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Impressions on Final Fantasy I: Dawn of Souls</title>
      <link>https://vfoley.xyz/ff1-dawn-of-souls/</link>
      <pubDate>Sat, 11 Feb 2017 07:40:32 -0500</pubDate>
      
      <guid>https://vfoley.xyz/ff1-dawn-of-souls/</guid>
      <description>&lt;p&gt;Following my &lt;a href=&#34;https://vfoley.xyz/ff1-review/&#34;&gt;playthrough&lt;/a&gt; of the original Final Fantasy for the NES, I played the remake for the Gameboy Advance, Final Fantasy I: Dawn of Souls.  The game wasn&amp;rsquo;t very hard, and since I knew exactly what I had to do, I didn&amp;rsquo;t wander around aimless and was able to finish it in roughly nine hours.&lt;/p&gt;
&lt;p&gt;The port to the GBA includes modernized graphics, sound, and music; modernized game play; quality of life additions; improved translation, longer dialogues with NPCs, and modernized names for magic spells; bug fixes; new side quests.  But surely the greatest quality of Dawn of Souls is that, even with all the improvements, the developers and artists have managed to make it look and feel like the original Final Fantasy.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Note: at the moment, I have not played Final Fantasy II: Dawn of Souls, so my comments are all based on my experience with Final Fantasy I: Dawn of Souls.)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;improved-graphics-and-music&#34;&gt;Improved graphics and music&lt;/h2&gt;
&lt;p&gt;To my untrained eye, the graphics of Dawn of Souls look most like Final Fantasy V on the SNES; larger and more detailed than FFIV, smaller than FFVI.  They capture the look-and-feel of the 16-bit era Final Fantasies (which, I must confess, is my favorite generation of games).  Although there was nothing wrong with the graphics of the original NES and they had their unique charm, I appreciate the more detailed graphics: I find that they contribute to making the world richer and fuller.  Look at the difference between the new Lich and the original Lich: she now looks bigger, badder, and more menacing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://vfoley.xyz/images/ff1-lich.png&#34; alt=&#34;Fight against Lich&#34;&gt;&lt;/p&gt;
&lt;p&gt;Dawn of Souls animates magic spells more richly than the original game could; the visual effects for the high-level spells are beautiful, recognizable, and convey the great power of black and white magic.  The spells used by enemies are also animated, and even when two enemies cast the same spells, the animations can differ.  Take for instance the ice storm cast by both Winter Wolves and White Dragons: to convey that the Dragons do more damage, the whole screen becomes white with snow and ice, while the wolves&amp;rsquo; attack only send a volley of hail toward your party.&lt;/p&gt;
&lt;p&gt;The music composed by Nobuo Uematsu for the Final Fantasy series is legendary, and the music of the original game was no exception, giving us the original motifs for the Prelude, the Final Fantasy Theme, and the battle and victory themes.  There is a detail I noticed in the soundtrack of the first game on the NES: none of the tracks seem to use the noise channel.  Listen to the &lt;a href=&#34;https://www.youtube.com/watch?v=XjPF3AwVPM4&#34;&gt;original battle theme&lt;/a&gt; and then compare with the &lt;a href=&#34;https://www.youtube.com/watch?v=mnUNGZMznu0&#34;&gt;Dawn of Souls battle theme&lt;/a&gt;; the drums in the latter make the track more energetic and better capture the excitement of battle.  I do not know if the absence of the noise channel on the original version was due to a technical limitation (e.g., using it for attack sound effects) or if Uematsu had yet to figure out how to best use this extra channel.  Regardless, the soundtrack of the new game (which was supervised by Uematsu himself) stays true to the original and adds a few track of its own: rather than fighting fiends with the standard battle theme, new tracks were composed for those important showdowns.&lt;/p&gt;
&lt;h2 id=&#34;modernized-game-play-and-quality-of-life&#34;&gt;Modernized game play and quality of life&lt;/h2&gt;
&lt;p&gt;I mentioned in my impressions of FFI that I enjoyed the simpler and slower battle system; I&amp;rsquo;m happy the developers decided to keep the turn-based fighting system rather than replace it with a faster-moving ATB-like system.  Like the NES version, the player selects an action for each character, and then those actions are performed, interspersed with enemy actions.  Contrary to the NES version, however, the concept of ineffective attacks has been eliminated: if an enemy dies before it was attacked by one of your party member, a new enemy will automatically be re-targeted.  This change certainly pleases many gamers, and makes the game more accessible to newer players.  I mentioned before that ineffective attacks opened an extra tactical dimension, so it would have been cool if they could be re-enabled through an option.  I believe that the PSX or PSP version offer such an option.&lt;/p&gt;
&lt;p&gt;The magic system has been modernized and will feel more familiar to anyone who has played a RPG in the last 20 years.  Rather than having a fixed amount of charges per spell level, casters have MP that they can use to cast any spell.  Tents and cottages restore MP and Ether have been added to the game; caster characters can now use their magic repertoire more freely.  A welcome improvement over the NES version involves multi-target spells: rather than acting on one character at a time, they act on all targets at once.  I&amp;rsquo;m sure anyone how has casted FIR3 on 9 undead or had to wait for 6 WhWolf to cast IceStorm in the original NES version will appreciate the quicker fights.  The spell names have also been changed: the nomenclature that is now pervasive in Final Fantasy has been back-ported.  FIR3 is now Firaga, LIT2 is Thundara, etc.&lt;/p&gt;
&lt;p&gt;Many enemies are now weaker, but the bosses are tougher.  None of the fiends were push-overs.  Chaos, who used to have 2000 HP in the original, now has a whooping 20,000 HP!  This buff made for an epic final showdown: my fighting characters kept hitting while my white mage did everything in her power to keep them alive.  It took a solid 8-9 minutes before my Light Warriors finally prevailed.  That&amp;rsquo;s the way boss battles ought to be!&lt;/p&gt;
&lt;p&gt;A number of quality of life improvements are also included in the game.  A surprising feature for a Final Fantasy game is the ability to save anywhere, and not just when using tents or staying at an inn; maybe this was to allow players who play on the go (e.g., train or bus) to enjoy a few minutes of the game and then quickly save their progress.  The game also has dashing, making trips into town quicker and descending into dungeons less of a drudgery.  Buying items in shops can be done in bulk rather than buying one heal potion at a time (yes!)  Similarly, when using an item or a spell on a character in the menu, pressing &lt;code&gt;A&lt;/code&gt; multiple times uses that item/casts that spell multiple times; healing your party with items after a difficult battle is thus faster and less of a chore.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also a point I didn&amp;rsquo;t think I&amp;rsquo;d ever need to mention in a Final Fantasy game: the controls are responsive.  I am currently playing Final Fantasy IV Advance on the GBA and there is a &lt;strong&gt;lot&lt;/strong&gt; of input lag!  For instance, there is a 1 second delay between the time I press &lt;code&gt;A&lt;/code&gt; to use a potion and the time that it actually applies!  Fortunately, the controls in Final Fantasy Dawn of Souls are very responsive and you don&amp;rsquo;t lose an action because the game was busy at that time.&lt;/p&gt;
&lt;h2 id=&#34;fixed-bugs&#34;&gt;Fixed bugs&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s no secret that the Final Fantasy games have been plagued with bugs: status ailments that didn&amp;rsquo;t work, stats that had no impact on your character, and even game crashing bugs (e.g., the draw ability in FFVI on the SNES).  The original Final Fantasy was no exception: many spells didn&amp;rsquo;t work, the class ability of the thief was incorrectly programmed, etc.  Final Fantasy Dawn of Souls fixes most of those bugs.  The most disappointing aspect of gameplay bugs is when they take away tactical depth.  I&amp;rsquo;m happy that I can rely on all my spells when making a decision: using the Temper spell is now a great way to boost the attacking abilities of your fighters.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I thought Final Fantasy I: Dawn of Souls was a terrific game, and I would not hesitate to recommend it.  People completely new to the series will appreciate a straight-forward game with a simple system while veterans of the series will enjoy a solid port that brings back all the nostalgia and leaves many of the pain points in the past.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My impressions of Final Fantasy for the NES</title>
      <link>https://vfoley.xyz/ff1-review/</link>
      <pubDate>Sat, 04 Feb 2017 14:09:13 -0500</pubDate>
      
      <guid>https://vfoley.xyz/ff1-review/</guid>
      <description>&lt;p&gt;A week ago, I finished my first playthrough of the original Final Fantasy for the NES.  In the past, I had not been super interested in playing this episode since it was said to be (understandably) rough around the edges, being the first entry in the franchise.  A few factors changed my mind: first, I heard great comments on the &lt;a href=&#34;https://www.youtube.com/watch?v=NexyGZCZ9KM&#34;&gt;FF1 run at AGDQ 2017&lt;/a&gt; by Feasel and Gyre and I was looking forward to watching a solid speedrun; second, I discovered that a couple of my coworkers were big fans of this game; lastly, I&amp;rsquo;ve been thinking that there is a void in my video game culture due to not having played (or even watched) the early episodes of Final Fantasy.  For these reasons, I decided to go ahead and play the game.&lt;/p&gt;
&lt;h2 id=&#34;what-i-liked&#34;&gt;What I liked&lt;/h2&gt;
&lt;p&gt;I was pleasantly surprised by the game, very much so!  Despite its age, the limitations of the platform on which it ran, and that there were no other Final Fantasy games to turn to for inspiration, I thought that it was a much more solid entry than I&amp;rsquo;d given it credit for.  Here are some of the features of the game, in no particular order, that I found genuinely interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The combat system&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By far my favorite feature of Final Fantasy is its combat system.  Final Fantasy does not have the ATB combat system that became well known with the entries on the SNES and Playstation; before a turn, you select the actions for your characters, and then they execute those actions, with monster attacks interspersed in between.  I&amp;rsquo;m not sure that I know how the turns are selected: purely random maybe?&lt;/p&gt;
&lt;p&gt;I like this system, because it is slow, and it gives me time to think (roguelikers will appreciate, I&amp;rsquo;m sure).  I can take my time to figure out what enemy formation I&amp;rsquo;m fighting, how much I think each of my attacks might do, and formulate an attack plan.  If I make a mistake during action selection, I can simply press &lt;code&gt;B&lt;/code&gt; and correct my error.  This very forgiving mechanic can allow you to realize that there is a better plan of attack while you are selecting your commands.&lt;/p&gt;
&lt;p&gt;Most people have heard of ineffective attacks: if an enemy dies, every command that targets this enemy afterwards will whiff rather than re-targeting another enemy.  I had thought initially that this was going to be extremely tedious, but it turned out that this opens up an extra tactical dimension: should all your party members target one enemy to ensure it dies in this turn, or should you spread your attacks to end the fight more quickly?  It also pushes you to estimate an enemy&amp;rsquo;s hit points (I got really good at keeping an upper-bound on max HP) and guess-timate if you need one, two, or more attacks to defeat it.  It also makes fights more tense, because you can&amp;rsquo;t hold down &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The party selection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As far as I know, Final Fantasy is unique within the franchise in allowing you to select the members of your party, and not allowing you to change (e.g., you can change that nature of an FF5 party by switching jobs).  I finished my own playthrough with two fighters, one red mage, and one black mage.  I had my share of difficulties since I did not have a white mage; for instance, in the Ice Cave, seeing mages was extremely scary, because I did not have a party member that could use the LIFE spell (and the game doesn&amp;rsquo;t have Phoenix Downs).  The speed-run I mentioned earlier used two fighters and two red mages; my colleagues&amp;rsquo; parties were four fighters and fighter, white mage, two black belts respectively.  Some crazy gamers have won the game using a party of only white mages or black mages, etc.  This gives the game a lot of replayability, and many ways to increase the difficulty of the game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The plot and the game world&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Final Fantasy is not a complicated game, it&amp;rsquo;s even simplistic at times.  Yet, I thought it was charming, and because of the NES&amp;rsquo;s technical limitations, there was only one side quest (the Castle of Ordeals), and everything else was very straight-forward: go fetch a KEY to get TNT so that you can have access to later dungeons.  The NPCs have limited dialogue, but they can still gives you some hints about where you need to go and what you need to do to progress; for instance, you need to bring SLAB to Dr. Unne to understand the Lufenian language, and an NPC gives you a hint that this is the person you need to go see, but they forgot his name.  The game also introduces many elements that would become staples of the series: black and white magic, different races, Bahamut, crystals, an airship, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The beastiary&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Many of the infamous enemies of Final Fantasy were in the very first entry: cockatrices, mind flayers, huge worms, etc.  And many of those enemies are &lt;em&gt;scary&lt;/em&gt;: I don&amp;rsquo;t think I ever actually fought mind flayers, I just ran away and hoped they didn&amp;rsquo;t kill any of my party members.  Similarly, a group of 9 cockatrices ambushing you is sure to make even the atheist players pray to some random deity to avoid getting stoned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The dungeons&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although the NES&amp;rsquo;s technical capabilities did not allow a lot of variety and flexibility, each dungeon really felt distinct from the others.  The colors, the enemies, and the music all contributed to create a unique ambiance for each place you visited.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The music&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nobuo Uematsu is now a legendary figure in the video game world: his work was instrumental to the series&amp;rsquo; popularity, and today millions of gamers remember fondly the tunes he composed.  Final Fantasy on the NES had a very basic sound system (&lt;a href=&#34;https://www.youtube.com/watch?v=q_3d1x2VPxk&#34;&gt;see this video&lt;/a&gt; for a nice primer), yet Uematsu found a way to make that simple system sing.  I especially enjoyed Matyoa&amp;rsquo;s theme, the battle song, and Gurgu Volcano.&lt;/p&gt;
&lt;h2 id=&#34;what-i-liked-less&#34;&gt;What I liked less&lt;/h2&gt;
&lt;p&gt;Final Fantasy is a great game, but it is certainly not without its flaws.  None of the flaws are fatal, but they can detract a little bit from the game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bugs galore&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the most obvious problem with the game is the amount of bugs that you&amp;rsquo;ll see, even in a normal playthrough.  There are many magic spells that never work (e.g. TMPR), the INT stat is bugged and doesn&amp;rsquo;t do anything, the thief&amp;rsquo;s special aptitude for running away doesn&amp;rsquo;t work, etc.  There are no showstopper bugs as far as I know, but if a magic spell doesn&amp;rsquo;t seem to do anything, it&amp;rsquo;s very difficult to know if it&amp;rsquo;s because the enemy is resistant/immune to it, or because there is a programming problem.  One often has to resort to FAQs to know if it&amp;rsquo;s worth buying a spell or not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The magic system&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t care too much for the magic system where you have a limited number of charges for a spell level, and when those are gone, you need to go to an inn or use a house to recharge them.  When it&amp;rsquo;s your first playthrough, it&amp;rsquo;s difficult to know if you should keep those charges, or if it&amp;rsquo;s fine to use them, so I ended up using magic only when facing bosses, or when grinding.  Speaking of grinding&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some grinding required&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I had to grind quite a few times during the game to reach a level that would allow me to complete a dungeon.  Today, such a requirement is considered tedious, but it&amp;rsquo;s a bit more understandable for a game like Final Fantasy that was exploring the genre for the first time.  I still did not enjoy spending 30 minutes here and there just fighting enemies to have a sufficiently high enough level to go through the next phase of the game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Buying items&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The game has very few consumables: for example, the only healing item is a HEAL potion which gives you back 30 HP.  As we mentioned, spell charges are limited, and cannot be recharged in a dungeon, so HEAL potions are essential to keep your party alive.  The problem is that you buy consumables one at a time.  It takes quite a lot of time to get 99 of them.  Fortunately, an emulator can lessen the burden by accelerating the speed of the game, and allowing you to keep the Turbo &lt;code&gt;A&lt;/code&gt; button pressed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limited saving&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since you can only save you game in inns or on the overworld using a tent/cottage/house, going through a dungeon can be really nerve-racking.  Although it adds to the tension of the game (which I liked), it&amp;rsquo;s really tempting to use save states in an emulator to ensure that you don&amp;rsquo;t lose all your progress should you have an unfortunate encounter.&lt;/p&gt;
&lt;h2 id=&#34;parting-words&#34;&gt;Parting words&lt;/h2&gt;
&lt;p&gt;If you are a fan of the Final Fantasy series and you would like to discover the humble beginnings of one of the most popular and beloved series, I can heartily recommend that you give Final Fantasy a try.  Desprite being primitive in comparison to recent entries, I&amp;rsquo;m sure you&amp;rsquo;ll appreciate how this little seed of a game sprouted a large and strong tree of a series.&lt;/p&gt;
&lt;p&gt;In my next entry, I&amp;rsquo;ll discuss &lt;em&gt;Final Fantasy: Dawn of Souls&lt;/em&gt;, the port of Final Fantasy and Final Fantasy II to the Gameboy Advance.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>rebirth</title>
      <link>https://vfoley.xyz/rebirth/</link>
      <pubDate>Thu, 26 Jan 2017 22:03:24 -0500</pubDate>
      
      <guid>https://vfoley.xyz/rebirth/</guid>
      <description>&lt;p&gt;I used to have a blog, a long time ago, where I&amp;rsquo;d sometimes write incoherent ramblings about coding, politics, and any other subject that struck my fancy.  After a long hiatus, let&amp;rsquo;s get going again!&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
